AngularJS: ng-repeat с динамическим списком, без восстановления всего дерева DOM?
Я использую ng-repeat в строке таблицы с данными из массива JSON, полученным с сервера. Моя цель - автоматически обновлять список всякий раз, когда элемент добавляется, удаляется или изменяется на сервере, не затрагивая неизмененные элементы. В финальной реализации эти строки таблицы также содержат привязанные к двунаправленным элементам <input>
и <select>
для отправки обновлений обратно на сервер. Некоторые из доступных опций в элементах <select>
также будут сгенерированы с использованием директив ng-repeat из другого списка, который также может измениться.
До сих пор каждый раз, когда новый массив поступает с сервера (в настоящее время опрошено каждые две секунды), весь список ng-repeat удаляется и регенерируется. Это проблематично, поскольку оно мешает выбору текста, уничтожает поля ввода, даже если они в настоящее время редактируются пользователем, и, вероятно, работает намного медленнее, чем необходимо.
Я написал другие веб-приложения, которые делают то, что я хочу, используя jQuery и DOM-манипуляции, но код заканчивается действительно волосатым, и разработка занимает много времени. Я надеюсь использовать AngularJS и привязку данных, чтобы выполнить это во фракции кода и времени.
Итак, вот вопрос: можно ли обновить массив поддержки таким образом, но изменить только элементы DOM, соответствующие фактически изменяемым элементам/свойствам?
Здесь минимальный тестовый пример, который имитирует периодический опрос с использованием жестко закодированного массива в таймере (см. его в режиме http://jsfiddle.net/DWrmP/). Обратите внимание, что выбор текста очищается каждые 500 мс из-за стирания и воссоздания элементов.
HTML
<body ng-app="myApp">
<table ng-controller="MyController">
<tr ng-repeat="item in items | orderBy:'id'">
<td>{{item.id}}</td>
<td>{{item.data}}</td>
</tr>
</table>
</body>
JavaScript
angular.module('myApp', []).controller(
'MyController', [
'$scope', '$timeout',
function($scope, $timeout) {
$scope.items = [
{ id: 0, data: 'Zero' }
];
function setData() {
$scope.items = [
{ id: 1, data: 'One' },
{ id: 2, data: 'Two' },
{ id: 5, data: 'Five' },
{ id: 4, data: 'Four' },
{ id: 3, data: 'Three' }
];
$timeout(setData, 500);
}
$timeout(setData, 500);
}
]
);
Ответы
Ответ 1
Для тех, кто находит это в google, страница ниже описывает функцию в AngularJS 1.2, которая помогает с этой проблемой:
http://www.bennadel.com/blog/2556-Using-Track-By-With-ngRepeat-In-AngularJS-1-2.htm
Изменить добавление: самые важные предложения из связанного сообщения, если связь когда-либо умирает:
С новым синтаксисом "track by" я могу теперь сообщить AngularJS, какое свойство объекта (или путь свойства) следует использовать для связывания объекта JavaScript с DOM node. Это означает, что я могу поменять местами объекты JavaScript, не разрушая узлы DOM, пока ассоциация "track by" все еще работает.
Ответ 2
Я верю, что эта статья объяснит, как работает ngRepeat
http://www.bennadel.com/blog/2443-Rendering-DOM-Elements-With-ngRepeat-In-AngularJS.htm
Итак, если вы храните объекты в коллекции - тогда да (i e $hashKey persist)
В противном случае - no
Ответ 3
Я планирую самостоятельно создать следующее решение, хотя оно все еще находится в моем отставании продукта.
Проблема с ng-repeat заключается в удалении элементов из DOM, когда это необходимо для таблицы, это будет означать, что она изменит размер и таковую, но если данные динамические, они могут мерцать, потому что данные изменяются вокруг и размер таблицы меняется. Особенно во время пейджинга, потому что вся страница может еще не загрузиться.
Чтобы обойти это мерцание, таблица не должна менять количество строк. Вместо этого нужно ng-повторить "отображаемые" данные и просто изменить их по мере необходимости без добавления или удаления элементов из массива.