在编辑列表时禁用AngularJS中的orderBy

时间:2021-10-08 20:56:08

After applying orderBy in my list of input boxes if i edit any field it starts sorting immediately and i loose focus. I tried to dug in the angular code and found out they have applied something like $watch on the orderBy's attributes therefore whenever the value changes it sorts the list.Is there any way to disable orderBy while editing? I dont want to let the orderBy sort data while editing text. Any help will be appreciated

在我的输入框列表中应用orderBy之后,如果我编辑任何字段,它会立即开始排序,我就会失去焦点。我试图深入挖掘角码,发现它们在orderBy的属性上应用了$watch之类的东西,因此每当值发生变化时,它就对列表进行排序。有什么方法可以在编辑时禁用orderBy ?我不想让orderBy在编辑文本时对数据进行排序。如有任何帮助,我们将不胜感激

Here is my plunker

这是我的一美元

Note: I want to use orderBy & don't need any alternative like sorting the list from any controller itself. I just want the orderBy to sort the list once on page load and then remain quite.

注意:我想使用orderBy &不需要从任何控制器本身对列表进行排序。我只是希望orderBy在页面加载时对列表进行排序,然后保持不变。

8 个解决方案

#1


11  

I was using orderBy on a list that could be re-ordered using angular-sortable, and ran into a similar issue.

我在一个可以使用angular-sortable重新排序的列表上使用orderBy,并遇到了类似的问题。

My solution was to perform the ordering manually, by calling the orderBy filter inside the controller when the page was initialised, and then calling it subsequently when necessary, for example in a callback function after re-ordering the list.

我的解决方案是手动执行排序,在初始化页面时调用控制器内的orderBy过滤器,然后在必要时调用它,例如在重新排序列表之后调用回调函数。

#2


8  

You could override the directive to change the moment of the update to the moment you wish the reordering. You could also just not use ng-model and rely on a custom directive.

您可以重写指令,将更新的时刻更改为希望重新排序的时刻。您也可以不使用ng-model,而是依赖自定义指令。

This thread discuss overriding the input directive to change the model update to be triggered by tge blur event. Take a look at the fiddle.

这个线程讨论重写输入指令以更改tge模糊事件触发的模型更新。看看小提琴。

Although you might override the directive, you shouldn't do this, and the best solution, as explained and exemplified by @Liviu T. in the comments below would be to create a custom directive that removes the event keyup binding and adds a blur one. Here is directive code, and here is Liviu's plunker:

尽管您可能会重写该指令,但不应该这样做,最好的解决方案(如@Liviu T.在下面的注释中所解释和举例)是创建一个自定义指令,该指令删除事件keyup绑定并添加一个模糊的绑定。这是指令码,这是Liviu的柱塞:

app.directive('modelChangeBlur', function() {
    return {
        restrict: 'A',
        require: 'ngModel',
            link: function(scope, elm, attr, ngModelCtrl) {
            if (attr.type === 'radio' || attr.type === 'checkbox') return;

            elm.unbind('input').unbind('keydown').unbind('change');
            elm.bind('blur', function() {
                scope.$apply(function() {
                    ngModelCtrl.$setViewValue(elm.val());
                });         
            });
        }
    };
});
<input type="text" ng-model="variable" model-change-blur/>

Unfortunately, as Angular events are not namespaces, you will have to remove any previously added event.

不幸的是,由于角度事件不是名称空间,您将不得不删除任何先前添加的事件。

#3


2  

Following @CaioToOn works but it breaks in Angular 1.2.4 (possibly the whole 1.2.X branch). To get it to work you also need to declare the priority of the custom directive to be 1 (the input directive is 0). The directive then becomes:

@CaioToOn之后可以工作,但是它的角度是1.2.4(可能是整个1.2)。X分行)。要使其工作,还需要声明自定义指令的优先级为1(输入指令为0)。

app.directive('modelChangeBlur', function() {
return {
    restrict: 'A',
    priority: 1,
    require: 'ngModel',
        link: function(scope, elm, attr, ngModelCtrl) {
        if (attr.type === 'radio' || attr.type === 'checkbox') return;

        elm.unbind('input').unbind('keydown').unbind('change');
        elm.bind('blur', function() {
            scope.$apply(function() {
                ngModelCtrl.$setViewValue(elm.val());
            });         
        });
    }
};

});

});

See http://plnkr.co/edit/rOIH7W5oRrijv46f4d9R?p=preview and https://*.com/a/19961284/1196057 for related priority fix.

参见http://plnkr.co/edit/rOIH7W5oRrijv46f4d9R?p=preview和https://*.com/a/19961284/1196057进行相关的优先级修复。

#4


2  

A different approach may be to not loose focus to begin with. If your main problem is that your loosing focus, then instead of disabling orderBy, add this directive to your input:

另一种方法可能是一开始就不要分散注意力。如果您的主要问题是您失去了焦点,那么不要禁用orderBy,将此指令添加到您的输入中:

app.directive("keepFocus", ['$timeout', function ($timeout) {
    /*
    Intended use:
        <input keep-focus ng-model='someModel.value'></input>
    */
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function ($scope, $element, attrs, ngModel) {

            ngModel.$parsers.unshift(function (value) {
                $timeout(function () {
                    $element[0].focus();
                });
                return value;
            });

        }
    };
}])

Then just:

然后:

<input keep-focus ng-model="item.name"/>

I know this does not directly answer you question, but it might help solve the underlying problem.

我知道这并不能直接回答你的问题,但它可能有助于解决潜在的问题。

#5


0  

There's no easy or straightforward way to accomplish what you want, but there are some options. You would have to work without ng-model, and instead use the blur event:

没有简单或直接的方法来完成你想要的,但是有一些选择。你将不得不在没有ng-model的情况下工作,取而代之的是使用模糊事件:

JS:

JS:

var app = angular.module('myapp', []);

app.controller('MainCtrl', function($scope) {
  $scope.items = [
    { name: 'foo', id: 1, eligible: true },
    { name: 'bar', id: 2, eligible: false },
    { name: 'test', id: 3, eligible: true }
  ];

  $scope.onBlur = function($event, item){
    // Here you find the target node in your 'items' array and update it with new value
    _($scope.items).findWhere({id: item.id}).name = $event.currentTarget.value;
  };
});

app.directive('ngBlur', function($parse) {
  return function ( scope, element, attr ) {
    var fn = $parse(attr.ngBlur);
    element.bind( 'blur', function ( event, arg ) {
      scope.$apply( function(){
        fn(scope, {
          $event : event,
          arg: arg
        });
      });
    });
  };
});

HTML:

HTML:

<div ng-controller="MainCtrl">
  <div ng-repeat="item in items | orderBy:'name'" >
    <input value="{{item.name}}" ng-blur="onBlur($event, item)"/>
  </div>
</div>

Plunker.

砰砰作响。

But be aware that this would break the two-way binding between the model and the view.

但是要注意,这将打破模型和视图之间的双向绑定。

#6


0  

You can create custom filter and call that only when necessary. Example when you click on 'Grid header' for sorting or after dynamically adding/removing values to array, or simply click of a button(Refresh Grid)

您可以创建自定义过滤器,并在必要时调用它。例如,当您单击“网格头”进行排序或在向数组动态添加/删除值之后,或者仅仅单击按钮(刷新网格)

You need to dependency Inject Angular filter and sort filter

你需要依赖注入角滤波器和排序滤波器

angular
   .module('MyModule')
   .controller('MyController', ['filterFilter', '$filter', MyContFunc])

     function ExpenseSubmitter(funcAngularFilter, funcAngularFilterOrderBy) {
       oCont = this;
       oCont.ArrayOfData = [{
         name: 'RackBar',
         age: 24
       }, {
         name: 'BamaO',
         age: 48
       }];
       oCont.sortOnColumn = 'age';
       oCont.orderBy = false;
       var SearchObj = {
         name: 'Bama'
       };

       oCont.RefreshGrid = function() {
         oCont.ArrayOfData = funcAngularFilter(oCont.ArrayOfData, SearchObj);
         oCont.ArrayOfData = funcAngularFilterOrderBy('orderBy')(oCont.ArrayOfData, oCont.sortOnColumn, oCont.orderBy);
   }
 }

and call in HTML something like:

在HTML中调用如下内容:

<table>
  <thead>
    <tr>
      <th ng-click="oCont.sortOnColumn = 'age'; oCont.RefreshGrid()">Age</th>
      <th ng-click="oCont.sortOnColumn = 'name'; oCont.RefreshGrid()">Name</th>
    </tr>
  </thead>
  <tbody>
    <tr ng-repeat="val in oCont.ArrayOfData">
      <td>{{val.age}}</td>
      <td>{{val.name}}</td>
    </tr>
  </tbody>
</table>

#7


0  

You can freeze the current ordering while you are editing. Say your html looks like this:

您可以在编辑时冻结当前的排序。假设你的html看起来是这样的:

<tbody ng-repeat="item in items | orderBy:orderBy:reverse">
    <tr ng-click="startEdit()">
      <td>{{item.name}}</td>
    </tr>
</tbody>

In your controller you write:

在您的控制器中,您写道:

var savedOrderBy, savedReverse;
$scope.startEdit() = function() {
    $scope.items = $filter('orderBy')($scope.items, $scope.orderby, $scope.reverse);

    for (var i = 0; i < $scope.items.length; ++i) {
        if (i < 9999) { 
            $scope.items[i]['pos'] = ("000" + i).slice(-4); 
        }
    }

    savedOrderBy = $scope.orderBy;
    savedReverse = $scope.reverse;
    $scope.orderBy = 'pos';
    $scope.reverse = false;
};

Before the user starts editing, you first sort the current items in exactly the same order that they currently appear in the page. You do that by calling the orderBy $filter() with the current sorting parameters.

在用户开始编辑之前,首先按照当前项在页面中出现的顺序对当前项进行排序。通过使用当前排序参数调用orderBy $filter()来实现这一点。

Then you go over your - now sorted - items, and add an arbitrary property (here "pos") and set it to the current position. I zero-pad it so that position 0002 collates before 0011. Maybe that is not necessary, no idea.

然后,检查您的-现在已排序的-项,并添加一个任意属性(这里的“pos”)并将其设置为当前位置。我对它进行了零填充,使0002的位置在0011之前进行排序。也许这是不必要的,不知道。

You normally want to remember the current ordering, here in the scope variables "savedOrder" and "savedReverse".

您通常希望记住当前的顺序,这里是作用域变量“savedOrder”和“savedReverse”。

And finally you tell angular to sort by that new property "pos" and voilà the table order is frozen, because that property simply does not change while editing.

最后,你通过新的属性“pos”告诉angle进行排序,这样表的顺序就被冻结了,因为这个属性在编辑时不会改变。

When you are done editing, you have to do the opposite. You restore the old ordering from the scope variables "savedOrder" and "savedReverse":

当你完成编辑时,你必须做相反的事情。您从范围变量“savedOrder”和“savedReverse”中恢复旧的顺序:

$scope.endEdit = function() {
    $scope.orderBy = savedOrderBy;
    $scope.reverse = reverse;
};

If the order of the $scope.items array matters for you, you would also have to sort it again to its original ordering.

如果订单的范围是$。条目数组对您来说很重要,您还需要将它重新排序到它的原始排序。

#8


0  

Try using a scope variable to change the order. In this case, when you are going to order, you call a function in your controller that changes the variable order value to the field you want to order by, and when you are editing, you reset it.

尝试使用范围变量来更改顺序。在这种情况下,当你要排序时,你调用你的控制器中的一个函数,它将变量order值更改为你想要排序的字段,当你编辑时,你重置它。

Example:

例子:

<li ng-repeat="item in filtered = (items | filter:search) |  orderBy:order:rever" >

So here we have the variable "order" to tell the ng-repeat by which field the list must be ordered. A button calls a function in the controller that changes the "order" value.

这里我们有一个变量“order”来告诉ng-repeat列表必须按哪个字段排序。按钮调用控制器中的一个函数,该函数更改“order”值。

<button type="button" id="orderName" click="changeOrder('item.name')" >Name order </button>

<button type="button" id="orderDate" click="changeOrder('item.date')" >Date order </button>`

And then, in the changeOrder function

然后,在改变序函数中

$scope.order = param;

Where 'param' is the field you want to order by. If you don't do anything else, you are going to have the same problem you had, so then, after you have assigned the correct value to the order variable you go

“param”是您想要订购的字段。如果你不做其他的事情,你会遇到同样的问题,所以,在你把正确的值分配给顺序变量之后。

$scope.order = "";

Which resets the ordering. The result is that the ordering is just going to be effective when the button is pressed and then it wont order again unless you press the button again. This can be changed so it orders again when, for example, you have finished editing an item, as you wanted.

重置命令。结果是,当按下按钮时,排序就会生效,然后它就不会再次排序,除非你再次按下按钮。可以对它进行更改,以便当您按自己的意愿编辑完一个项目时,它再次进行排序。

#1


11  

I was using orderBy on a list that could be re-ordered using angular-sortable, and ran into a similar issue.

我在一个可以使用angular-sortable重新排序的列表上使用orderBy,并遇到了类似的问题。

My solution was to perform the ordering manually, by calling the orderBy filter inside the controller when the page was initialised, and then calling it subsequently when necessary, for example in a callback function after re-ordering the list.

我的解决方案是手动执行排序,在初始化页面时调用控制器内的orderBy过滤器,然后在必要时调用它,例如在重新排序列表之后调用回调函数。

#2


8  

You could override the directive to change the moment of the update to the moment you wish the reordering. You could also just not use ng-model and rely on a custom directive.

您可以重写指令,将更新的时刻更改为希望重新排序的时刻。您也可以不使用ng-model,而是依赖自定义指令。

This thread discuss overriding the input directive to change the model update to be triggered by tge blur event. Take a look at the fiddle.

这个线程讨论重写输入指令以更改tge模糊事件触发的模型更新。看看小提琴。

Although you might override the directive, you shouldn't do this, and the best solution, as explained and exemplified by @Liviu T. in the comments below would be to create a custom directive that removes the event keyup binding and adds a blur one. Here is directive code, and here is Liviu's plunker:

尽管您可能会重写该指令,但不应该这样做,最好的解决方案(如@Liviu T.在下面的注释中所解释和举例)是创建一个自定义指令,该指令删除事件keyup绑定并添加一个模糊的绑定。这是指令码,这是Liviu的柱塞:

app.directive('modelChangeBlur', function() {
    return {
        restrict: 'A',
        require: 'ngModel',
            link: function(scope, elm, attr, ngModelCtrl) {
            if (attr.type === 'radio' || attr.type === 'checkbox') return;

            elm.unbind('input').unbind('keydown').unbind('change');
            elm.bind('blur', function() {
                scope.$apply(function() {
                    ngModelCtrl.$setViewValue(elm.val());
                });         
            });
        }
    };
});
<input type="text" ng-model="variable" model-change-blur/>

Unfortunately, as Angular events are not namespaces, you will have to remove any previously added event.

不幸的是,由于角度事件不是名称空间,您将不得不删除任何先前添加的事件。

#3


2  

Following @CaioToOn works but it breaks in Angular 1.2.4 (possibly the whole 1.2.X branch). To get it to work you also need to declare the priority of the custom directive to be 1 (the input directive is 0). The directive then becomes:

@CaioToOn之后可以工作,但是它的角度是1.2.4(可能是整个1.2)。X分行)。要使其工作,还需要声明自定义指令的优先级为1(输入指令为0)。

app.directive('modelChangeBlur', function() {
return {
    restrict: 'A',
    priority: 1,
    require: 'ngModel',
        link: function(scope, elm, attr, ngModelCtrl) {
        if (attr.type === 'radio' || attr.type === 'checkbox') return;

        elm.unbind('input').unbind('keydown').unbind('change');
        elm.bind('blur', function() {
            scope.$apply(function() {
                ngModelCtrl.$setViewValue(elm.val());
            });         
        });
    }
};

});

});

See http://plnkr.co/edit/rOIH7W5oRrijv46f4d9R?p=preview and https://*.com/a/19961284/1196057 for related priority fix.

参见http://plnkr.co/edit/rOIH7W5oRrijv46f4d9R?p=preview和https://*.com/a/19961284/1196057进行相关的优先级修复。

#4


2  

A different approach may be to not loose focus to begin with. If your main problem is that your loosing focus, then instead of disabling orderBy, add this directive to your input:

另一种方法可能是一开始就不要分散注意力。如果您的主要问题是您失去了焦点,那么不要禁用orderBy,将此指令添加到您的输入中:

app.directive("keepFocus", ['$timeout', function ($timeout) {
    /*
    Intended use:
        <input keep-focus ng-model='someModel.value'></input>
    */
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function ($scope, $element, attrs, ngModel) {

            ngModel.$parsers.unshift(function (value) {
                $timeout(function () {
                    $element[0].focus();
                });
                return value;
            });

        }
    };
}])

Then just:

然后:

<input keep-focus ng-model="item.name"/>

I know this does not directly answer you question, but it might help solve the underlying problem.

我知道这并不能直接回答你的问题,但它可能有助于解决潜在的问题。

#5


0  

There's no easy or straightforward way to accomplish what you want, but there are some options. You would have to work without ng-model, and instead use the blur event:

没有简单或直接的方法来完成你想要的,但是有一些选择。你将不得不在没有ng-model的情况下工作,取而代之的是使用模糊事件:

JS:

JS:

var app = angular.module('myapp', []);

app.controller('MainCtrl', function($scope) {
  $scope.items = [
    { name: 'foo', id: 1, eligible: true },
    { name: 'bar', id: 2, eligible: false },
    { name: 'test', id: 3, eligible: true }
  ];

  $scope.onBlur = function($event, item){
    // Here you find the target node in your 'items' array and update it with new value
    _($scope.items).findWhere({id: item.id}).name = $event.currentTarget.value;
  };
});

app.directive('ngBlur', function($parse) {
  return function ( scope, element, attr ) {
    var fn = $parse(attr.ngBlur);
    element.bind( 'blur', function ( event, arg ) {
      scope.$apply( function(){
        fn(scope, {
          $event : event,
          arg: arg
        });
      });
    });
  };
});

HTML:

HTML:

<div ng-controller="MainCtrl">
  <div ng-repeat="item in items | orderBy:'name'" >
    <input value="{{item.name}}" ng-blur="onBlur($event, item)"/>
  </div>
</div>

Plunker.

砰砰作响。

But be aware that this would break the two-way binding between the model and the view.

但是要注意,这将打破模型和视图之间的双向绑定。

#6


0  

You can create custom filter and call that only when necessary. Example when you click on 'Grid header' for sorting or after dynamically adding/removing values to array, or simply click of a button(Refresh Grid)

您可以创建自定义过滤器,并在必要时调用它。例如,当您单击“网格头”进行排序或在向数组动态添加/删除值之后,或者仅仅单击按钮(刷新网格)

You need to dependency Inject Angular filter and sort filter

你需要依赖注入角滤波器和排序滤波器

angular
   .module('MyModule')
   .controller('MyController', ['filterFilter', '$filter', MyContFunc])

     function ExpenseSubmitter(funcAngularFilter, funcAngularFilterOrderBy) {
       oCont = this;
       oCont.ArrayOfData = [{
         name: 'RackBar',
         age: 24
       }, {
         name: 'BamaO',
         age: 48
       }];
       oCont.sortOnColumn = 'age';
       oCont.orderBy = false;
       var SearchObj = {
         name: 'Bama'
       };

       oCont.RefreshGrid = function() {
         oCont.ArrayOfData = funcAngularFilter(oCont.ArrayOfData, SearchObj);
         oCont.ArrayOfData = funcAngularFilterOrderBy('orderBy')(oCont.ArrayOfData, oCont.sortOnColumn, oCont.orderBy);
   }
 }

and call in HTML something like:

在HTML中调用如下内容:

<table>
  <thead>
    <tr>
      <th ng-click="oCont.sortOnColumn = 'age'; oCont.RefreshGrid()">Age</th>
      <th ng-click="oCont.sortOnColumn = 'name'; oCont.RefreshGrid()">Name</th>
    </tr>
  </thead>
  <tbody>
    <tr ng-repeat="val in oCont.ArrayOfData">
      <td>{{val.age}}</td>
      <td>{{val.name}}</td>
    </tr>
  </tbody>
</table>

#7


0  

You can freeze the current ordering while you are editing. Say your html looks like this:

您可以在编辑时冻结当前的排序。假设你的html看起来是这样的:

<tbody ng-repeat="item in items | orderBy:orderBy:reverse">
    <tr ng-click="startEdit()">
      <td>{{item.name}}</td>
    </tr>
</tbody>

In your controller you write:

在您的控制器中,您写道:

var savedOrderBy, savedReverse;
$scope.startEdit() = function() {
    $scope.items = $filter('orderBy')($scope.items, $scope.orderby, $scope.reverse);

    for (var i = 0; i < $scope.items.length; ++i) {
        if (i < 9999) { 
            $scope.items[i]['pos'] = ("000" + i).slice(-4); 
        }
    }

    savedOrderBy = $scope.orderBy;
    savedReverse = $scope.reverse;
    $scope.orderBy = 'pos';
    $scope.reverse = false;
};

Before the user starts editing, you first sort the current items in exactly the same order that they currently appear in the page. You do that by calling the orderBy $filter() with the current sorting parameters.

在用户开始编辑之前,首先按照当前项在页面中出现的顺序对当前项进行排序。通过使用当前排序参数调用orderBy $filter()来实现这一点。

Then you go over your - now sorted - items, and add an arbitrary property (here "pos") and set it to the current position. I zero-pad it so that position 0002 collates before 0011. Maybe that is not necessary, no idea.

然后,检查您的-现在已排序的-项,并添加一个任意属性(这里的“pos”)并将其设置为当前位置。我对它进行了零填充,使0002的位置在0011之前进行排序。也许这是不必要的,不知道。

You normally want to remember the current ordering, here in the scope variables "savedOrder" and "savedReverse".

您通常希望记住当前的顺序,这里是作用域变量“savedOrder”和“savedReverse”。

And finally you tell angular to sort by that new property "pos" and voilà the table order is frozen, because that property simply does not change while editing.

最后,你通过新的属性“pos”告诉angle进行排序,这样表的顺序就被冻结了,因为这个属性在编辑时不会改变。

When you are done editing, you have to do the opposite. You restore the old ordering from the scope variables "savedOrder" and "savedReverse":

当你完成编辑时,你必须做相反的事情。您从范围变量“savedOrder”和“savedReverse”中恢复旧的顺序:

$scope.endEdit = function() {
    $scope.orderBy = savedOrderBy;
    $scope.reverse = reverse;
};

If the order of the $scope.items array matters for you, you would also have to sort it again to its original ordering.

如果订单的范围是$。条目数组对您来说很重要,您还需要将它重新排序到它的原始排序。

#8


0  

Try using a scope variable to change the order. In this case, when you are going to order, you call a function in your controller that changes the variable order value to the field you want to order by, and when you are editing, you reset it.

尝试使用范围变量来更改顺序。在这种情况下,当你要排序时,你调用你的控制器中的一个函数,它将变量order值更改为你想要排序的字段,当你编辑时,你重置它。

Example:

例子:

<li ng-repeat="item in filtered = (items | filter:search) |  orderBy:order:rever" >

So here we have the variable "order" to tell the ng-repeat by which field the list must be ordered. A button calls a function in the controller that changes the "order" value.

这里我们有一个变量“order”来告诉ng-repeat列表必须按哪个字段排序。按钮调用控制器中的一个函数,该函数更改“order”值。

<button type="button" id="orderName" click="changeOrder('item.name')" >Name order </button>

<button type="button" id="orderDate" click="changeOrder('item.date')" >Date order </button>`

And then, in the changeOrder function

然后,在改变序函数中

$scope.order = param;

Where 'param' is the field you want to order by. If you don't do anything else, you are going to have the same problem you had, so then, after you have assigned the correct value to the order variable you go

“param”是您想要订购的字段。如果你不做其他的事情,你会遇到同样的问题,所以,在你把正确的值分配给顺序变量之后。

$scope.order = "";

Which resets the ordering. The result is that the ordering is just going to be effective when the button is pressed and then it wont order again unless you press the button again. This can be changed so it orders again when, for example, you have finished editing an item, as you wanted.

重置命令。结果是,当按下按钮时,排序就会生效,然后它就不会再次排序,除非你再次按下按钮。可以对它进行更改,以便当您按自己的意愿编辑完一个项目时,它再次进行排序。