【问题标题】:Disabling orderBy in AngularJS while editing the list在编辑列表时禁用 AngularJS 中的 orderBy
【发布时间】:2013-02-23 19:32:12
【问题描述】:

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

Here is my plunker

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

【问题讨论】:

  • 当服务器发送我的数据时,我让它包含一个附加列“sortBy”,其中包含我希望排序的字段,然后 ng-repeat 将其用于 orderBy。此字段不在编辑中,因此在我再次从服务器取回行之前不会更改。 IE。当我“保存”一条记录时,会从数据库中获取返回的数据,包括 sortBy,它会替换 $scope 中的同一行,因此只有在编辑完成后才会更新页面上的排序。

标签: angularjs angularjs-orderby


【解决方案1】:

您可以覆盖指令以将更新时刻更改为您希望重新排序的时刻。你也可以不使用ng-model 而依赖custom directive

This thread 讨论覆盖输入指令以更改由 tge blur 事件触发的模型更新。看看fiddle

尽管您可能会覆盖该指令,但您不应该这样做,最好的解决方案,正如 @Liviu T.comments below 中所解释和举例说明的那样,是创建一个自定义指令,删除事件 keyup 绑定并添加一个模糊的。这是指令代码,这里是Liviu's 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 事件不是命名空间,您必须删除之前添加的任何事件。

【讨论】:

  • 我建议您不要覆盖而是添加一个新指令,该指令仅在您需要的地方启用该行为plnkr.co/edit/yoUmEUMMzecNlbKmtgDq?p=preview
  • 很好的解决方案,但正如 cmets 中所建议的,我们不应该覆盖已经存在的解决方案。以及我不想破坏任何与视图的绑定,即使是按键事件
  • 我同意,并更新了问题以适应@LiviuT。解决方案。不幸的是,避免keydown 更新的唯一方法是删除已经绑定到元素的事件。 Liviu 解决方案的好处在于,您不会输给使用默认指令的其他时刻。
【解决方案2】:

没有简单或直接的方法来完成您想要的,但有一些选择。您将不得不在没有 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>

Plunker.

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

【讨论】:

  • 我确实与我页面中的其他元素绑定,我猜这些更改在我模糊输入框之前不会反映。正确的?如果我们可以取消/编辑 orderBy 以使其在我重新加载页面或通过任何按钮应用排序之前不会看到任何更改,那会不会更好。毫无疑问,您的解决方案很好,但我不想用 ng-model 破解。希望你能理解
  • orderBy 过滤器实际上并没有关注变化。它是 ng-repeat 指令,它监视您的 items 数组,并在您的 ng-model 更改后立即重复它。因此,您可以按照我建议的方式进行操作,也可以创建自定义 ng-repeat 指令,该指令不会监视更改,而是由其他(显式)方式触发。
【解决方案3】:

在@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 了解相关的优先级修复。

【讨论】:

  • 这很好,但我在网格中有一个复选框,当用户选中该项目时,该行会跳转到它的新排序位置。除了关闭订单之外,我不确定我能做些什么。
【解决方案4】:

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

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

【讨论】:

【解决方案5】:

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

你需要依赖注入Angular filtersort 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);
   }
 }

并在 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>

【讨论】:

    【解决方案6】:

    另一种方法可能是一开始就不要松懈。如果您的主要问题是失去焦点,那么不要禁用 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"/>
    

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

    【讨论】:

    • 这很有帮助,确实改善了我的情况,谢谢。但是,如果排序列中有一个复选框并且您选中它,那么该项目会按正确的顺序排列。有什么想法可以改进吗?
    【解决方案7】:

    您可以在编辑时冻结当前排序。假设您的 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 数组的顺序对您很重要,您还必须将其重新排序为原来的顺序。

    【讨论】:

      【解决方案8】:

      尝试使用范围变量来更改顺序。在这种情况下,当您要订购时,您会在控制器中调用一个函数,将变量 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;
      

      其中 'param' 是您要排序的字段。如果您不做任何其他事情,您将遇到与您相同的问题,因此,在您为 order 变量分配正确的值之后

      $scope.order = "";
      

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-09-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-12-05
        • 1970-01-01
        • 2016-07-29
        相关资源
        最近更新 更多