Как я могу запретить 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, но они не очень помогли:
- Отключение orderBy в AngularJS при редактировании списка (не понимаю, как применить ответ там к моему коду)
- https://stackru.com/questions/30845516/stop-ng-repeat-auto-sorting-your-objects-while-editing-text-box-and-checkbox-in (Нет ответа)
Вопрос: Как я могу предотвратить использование 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>
Я надеюсь, что все это имеет смысл (возможно, даже просто работает ™).