Что такое "отслеживание" в AngularJS и как оно работает?
Я не очень понимаю, как track by
работает и что он делает.
Моя главная цель - использовать его с ng-repeat
чтобы добавить немного точности.
3 ответа
С помощью track by
отслеживать строки и повторяющиеся значения
Обычно ng-repeat
отслеживает каждый элемент по самому элементу. Для данного массива objs = [ 'one', 'one', 2, 'five', 'string', 'foo']
, ng-repeat
пытается отслеживать изменения по каждому obj
в ng-repeat="obj in objs"
, Проблема в том, что у нас есть повторяющиеся значения и angular выдаст ошибку. Одним из способов решения этой проблемы является угловое отслеживание объектов другими способами. Для строк, track by $index
это хорошее решение, так как у вас нет других способов отследить строку.
track by
и запуск дайджеста и ввода фокусов
Вы намекаете на то, что вы немного новичок в угловых. Цикл дайджеста происходит, когда angular выполняет исчерпывающую проверку каждого отслеживаемого свойства, чтобы отразить любые изменения в соответствующем представлении; часто во время дайджеста происходит то, что ваш код изменяет другие наблюдаемые свойства, поэтому процедуру необходимо выполнить снова, пока angular не обнаружит больше изменений.
Например: вы нажимаете кнопку, чтобы обновить модель с помощью ng-click
Затем вы делаете что-то (я имею в виду то, что вы написали в обратном вызове, чтобы выполнить, когда пользователь делает щелчок), затем угловой цикл запуска дайджеста, чтобы обновить представление. Я не слишком ясно объясняю это, поэтому вам следует продолжить расследование, если это не прояснило ситуацию.
Итак, вернемся к track by
, Давайте использовать пример:
- вызвать сервис для возврата массива объектов
- обновить объект в массиве и сохранить объект
- после сохранения сервиса, в зависимости от того, что возвращает API, вы можете:
- заменить весь объект ИЛИ
- обновить значение существующего объекта
- отражать изменения в
ng-repeat
UI
То, как вы будете отслеживать этот объект, будет определять, как пользовательский интерфейс отражает изменения.
Это один из самых раздражающих UX, которые я когда-либо испытывал. Скажем, у вас есть таблица объектов, в каждой ячейке есть вход, где вы хотите оперативно редактировать свойства этих объектов. Я хочу изменить значение, затем on-blur
сохраните этот объект при перемещении в следующую ячейку для редактирования, пока вы можете ожидать ответа. Так что это вещь типа автосохранения. В зависимости от того, как вы настроили track by
утверждение, что вы можете потерять текущий фокус (например, поле, которое вы в настоящее время редактируете), когда ответ будет записан обратно в ваш массив объектов.
Когда вы добавляете track by
вы в основном указываете angular генерировать один элемент DOM для каждого объекта данных в данной коллекции.
Вы можете track by $index
если ваш источник данных имеет повторяющиеся идентификаторы.
Если вам нужно повторить повторяющиеся элементы, вы можете заменить поведение отслеживания по умолчанию своим собственным, используя отслеживание по выражению.
Пример:
[{id:1,name:'one'}, {id:1,name:'one too'}, {id:2,name:'two'}]
Попробуйте использовать повторяющиеся значения в ng-repeat
, вы получите ошибку, такую как:
Ошибка: ngRepeat: дублирует дубликат ключа в повторителе
Чтобы избежать такого рода проблем, вы должны использовать track by $index
, Например:
<ul>
<li ng-repeat="item in [1, 2, 3, 3] track by $index">
{{ item }}
</li>
</ul>
Вот как бы вы получили $index
во вложенных ng-repeat
:
<div ng-repeat="row in matrix">
<div ng-repeat="column in row">
<span>outer: {{$parent.$index}} inner: {{$index}}</span>
</div>
</div>
Вот некоторые ресурсы, которые могут вам помочь:
track by $index
документацияngRepeat
документация- 2014 codelord.net статья о
ng-repeat
производительность иtrack by
Вы должны использовать track by
только если вам нужно идти против поведения по умолчанию ng-repeat
который должен удалить дубликаты.
Вы можете отслеживать элементы, используя свойство области $index
или указание пользовательской функции.
Например:
<div ng-repeat="x in [42, 42, 43, 43] track by $index">
{{x}}
</div>
Показать все значения массива (42 отображается дважды).
Для справки: https://docs.angularjs.org/api/ng/directive/ngRepeat
Допустим, у нас есть следующий список:
<ul>
<li ng-repeat="item in items">
{{ item }}
</li>
</ul>
где элемент имеет следующую структуру:
{ 'id'=>id, 'name'=>name, 'description'=>description }
В этом списке нет никаких проблем, пока мы не захотим его обновить. Для нашего удобства мы заменяем список элементов другим обновленным списком элементов, как таковых:
items = newItems;
Однако в этом новом списке изменилось несколько пунктов. Большинство предметов остаются прежними. К сожалению, Angular не знает, как идентифицировать наши элементы и сопоставить их с соответствующими<li>
elements, поэтому он просто удаляет все элементы и создает их снова. В некоторых случаях это чрезвычайно затратно по производительности, и вот гдеtrack by
входит в обиход.
Добавив track by
предложение к элементу
<li ng-repeat="item in items track by item.id">
мы информируем Angular, что уникальный идентификатор наших товаров item.id
. Теперь Angular знает, что нужно воссоздавать не все элементы, а только элементы с новыми идентификаторами, и обновляет только остальные. Улучшение производительности в большинстве случаев является значительным. Кроме того, лично мне нравится, что я могу легче отслеживать свои элементы с помощью инструментов разработчика в моем браузере, потому что они не исчезают каждый раз, когда я их обновляю.