16

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

这是我的笨蛋

注意:我想使用 orderBy 并且不需要任何替代方法,例如从任何控制器本身对列表进行排序。我只希望 orderBy 在页面加载时对列表进行一次排序,然后保持不变。

4

8 回答 8

11

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

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

于 2014-03-06T10:42:30.643 回答
8

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

该线程讨论了覆盖输入指令以更改要由 tgeblur事件触发的模型更新。看看小提琴

尽管您可能会覆盖该指令,但您不应该这样做,正如@Liviu T下面的评论中解释和举例说明的那样,最好的解决方案是创建一个自定义指令,该指令删除事件 keyup 绑定并添加一个模糊. 这是指令代码,这是Liviu 的 plunker

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/>

不幸的是,由于 Angular 事件不是命名空间,您必须删除任何以前添加的事件。

于 2013-03-08T11:30:50.683 回答
3

一种不同的方法可能是一开始就不要失去重点。如果您的主要问题是失去焦点,那么不要禁用 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;
            });

        }
    };
}])

然后只是:

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

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

于 2015-08-10T21:15:58.217 回答
2

在@CaioToOn 之后工作,但它在 Angular 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());
            });         
        });
    }
};

});

有关相关优先级修复,请参阅http://plnkr.co/edit/rOIH7W5oRrijv46f4d9R?p=previewhttps://stackoverflow.com/a/19961284/1196057

于 2013-12-10T21:20:42.457 回答
0

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

您需要依赖注入 Angular过滤器排序过滤器

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);
   }
 }

并在 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>
于 2015-01-29T07:48:20.200 回答
0

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

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:

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

笨蛋

但请注意,这会破坏模型和视图之间的双向绑定。

于 2013-03-08T11:54:39.090 回答
0

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

例子:

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

所以这里我们有变量“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>`

然后,在 changeOrder 函数中

$scope.order = param;

其中“参数”是您要订购的字段。如果你不做任何其他事情,你将遇到同样的问题,所以,在你为 order 变量分配正确的值之后,你去

$scope.order = "";

这会重置排序。结果是,当按钮被按下时,排序才会生效,然后除非你再次按下按钮,否则它不会再次排序。这可以更改,以便在您完成编辑项目时再次订购,如您所愿。

于 2017-02-23T11:51:39.487 回答
0

您可以在编辑时冻结当前排序。假设您的 html 如下所示:

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

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

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;
};

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

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

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

最后,您告诉 angular 按该新属性“pos”进行排序,瞧,表格顺序被冻结,因为该属性在编辑时根本不会改变。

完成编辑后,您必须执行相反的操作。您从范围变量“savedOrder”和“savedReverse”恢复旧排序:

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

如果 $scope.items 数组的顺序对您很重要,您还必须将其重新排序为原始顺序。

于 2015-11-19T15:10:43.437 回答