如何防止 Angular 在编辑时重新排序我的列表?

How can I prevent Angular from re-sorting my list while editing?

我使用 Angular 创建了一个小应用程序来管理 Todolists。每个列表都有许多待办事项。每个 todo 都有属性 name、value1 和 value2。

每个列表应该按Angular自动排序,所以我使用了ng-repeat="todo in selectedList.todos | orderBy: todoOrderFilter":

  <ul class="list-group">
    <li class="list-group-item" ng-repeat="todo in selectedList.todos | orderBy: todoOrderFilter">

      <div>
        <span>{{todo.name}} (Value1: {{todo.value1}}, Value2 {{todo.value2}})</span>
        <button type="button" class="btn btn-warning btn-xs" ng-click="editTodo(todo)"><i class="icon-trash"></i> Edit</button>
        <button type="button" class="btn btn-danger btn-xs floatright" ng-click="deleteTodo(todo)"><i class="icon-trash"></i> Delete</button>
      </div>

    </li>
  </ul>

在我的控制器中,我这样定义订单过滤器:

$scope.todoOrderFilter = function (todo) {
    return todo.value1 * todo.value2;
};

在我尝试使每一行都可编辑之前,这到目前为止效果很好。为此,我添加了一个带有输入元素的附加 <div> 来编辑每个 <li> 中的值,还添加了 ng-hide="todo.editing"ng-show="todo.editing" 以便能够将 on/off 编辑模式只需设置 todo.editing=truefalse;

完整的 HTML 看起来像这样:

  <ul class="list-group">
    <li class="list-group-item" ng-repeat="todo in selectedList.todos | orderBy: todoOrderFilter">

      <div ng-hide="todo.editing">
        <span>{{todo.name}} (Value1: {{todo.value1}}, Value2 {{todo.value2}})</span>
        <button type="button" class="btn btn-warning btn-xs" ng-click="editTodo(todo)"><i class="icon-trash"></i> Edit</button>
        <button type="button" class="btn btn-danger btn-xs floatright" ng-click="deleteTodo(todo)"><i class="icon-trash"></i> Delete</button>
      </div>

      <div ng-show="todo.editing">
        <input id="todoname" ng-model="todo.name" ng-enter="updateTodo(todo)" type="text" class="form-control marginBottom" placeholder="Todo speichern" aria-describedby="basic-addon2"></input>
        Value1: <input ng-model="todo.value1" ng-enter="updateTodo(todo)" type="text" class="form-control marginBottom" placeholder="Value1" aria-describedby="basic-addon2"></input>
        Value2: <input ng-model="todo.value2" ng-enter="updateTodo(todo)" type="text" class="form-control marginBottom" placeholder="Value2" aria-describedby="basic-addon2"></input>
        <button type="button" class="btn btn-default" ng-click="updateTodo(todo)">Save</button>
        <button type="button" class="btn btn-danger" ng-click="cancelUpdateTodo(todo)">Cancel</button>
      </div>

    </li>
  </ul>

编辑按钮处理程序:

$scope.editTodo = function(todo) {
    todo.editing = true;
};

这有点管用,但是当我编辑 value1 或 value2 的输入字段时,我的排序功能会自动触发,这会导致 <li> 元素上下跳动,这非常糟糕。

所以我基本上想要的是我的自动排序过滤器在 todo.editing=true.

时被禁用

到目前为止,我在 SO 上发现了这些类似的问题,但它们并没有真正帮助:


问题: 如何防止 Angular 在 todo.editing=true 时使用待办事项列表?

我坚信利用 Angular 团队已经为我们编写的代码,并以此为基础进行构建。因此,我认为这是装饰内置 orderBy 过滤器以接受第四个参数 (ignore) 的完美方案。

我自己还没有对此进行过非常彻底的测试,但它应该可以解决问题;

app.config(function ($provide) {
  $provide.decorator('orderByFilter', function ($delegate) {
    // Store the last ordered state.
    var previousState;

    return function (arr, predicate, reverse, ignore) {
      // If ignore evaluates to a truthy value, return the previous state.
      if (!!ignore) {
        return previousState || arr;
      }

      // Apply the regular orderBy filter.
      var order = $delegate.apply(null, arguments);

      // Overwrite the previous state with the most recent order state.
      previousState = order;

      // Return the latest order state.
      return order;
    }
  });
});

用法:

<div ng-repeat="d in data | orderBy:predicate:reverse:ignore">

<!-- in your case -->
<div ng-repeat="todo in selectedList.todos | orderBy:todoOrderFilter:false:todo.editing>

我希望所有这些都有意义(甚至 也行得通™)。

解决方案是编辑对象的副本而不是直接编辑它。然后,当用户完成编辑时,将原始对象替换为副本。