Как я могу запретить Angular пересортировать мой список во время редактирования?

Я создал небольшое приложение, использующее Angular для управления Todolists. В каждом списке есть несколько задач. Каждая задача имеет атрибуты 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" чтобы иметь возможность включать / выключать режим редактирования, просто установив todo.editing=true или же false;

Полный 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?

2 ответа

Решение

Решение состояло в том, чтобы отредактировать копию объекта вместо непосредственного редактирования. Затем замените исходный объект на копию, когда пользователь закончит редактирование.

Я твердо верю в использование кода, который уже был написан для нас командой 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>

Я надеюсь, что все это имеет смысл (возможно, даже просто работает ™).

Другие вопросы по тегам