Магия AngularJS: никогда не устанавливайте привязки к примитивам Если вы используете AngularJS , скорее всего, вы неоднократно сталкивались с правилом «Не привязывать привязки к примитивам».
В этом посте я более подробно рассмотрю пример, где использование примитивов создает проблемы: создание списка элементов, в котором каждый из элементов привязан к строке.
Наш пример
Допустим, вы работаете над приложением с книгами, и у каждой книги есть список тегов.Наивный способ разрешить пользователю редактировать теги:
(Вероятно, вам захочется добавить еще одно поле для добавления новых тегов и кнопку для удаления существующих тегов, но мы проигнорируем это ради простоты примера.<div ng-controller="bookCtrl"> <div ng-repeat="tag in book.tags"> <input type="text" ng-model="tag"> </div> </div>
) Доступна демо-версия нашего примера.
Здесь .
Попробуйте отредактировать одно из полей ввода.
Казалось бы, все в порядке.
Но это неправда.
Если вы присмотритесь, то увидите, что внесенные изменения не синхронизируются с массивом book.tags.
Это происходит потому, что ng-repeat создает дочернюю область для каждого тега, а на самом деле области видимости могут выглядеть так: bookCtrl scope = { tags: [ 'foo', 'bar', 'baz' ] }
ng-repeat child scopes: { tag: 'foo' }, { tag: 'bar' }, { tag: 'baz' }
В этих дочерних областях ng-repeat не создает двустороннюю привязку для значения тега.
Это означает, что при изменении первого поля ng-model просто меняет первую дочернюю область видимости на {tag:'something'}, и это никак не отражается на объекте книги.
Теперь вы увидели, как примитивы могут сыграть с вами плохую шутку.
Если бы мы использовали для каждого тега объекты вместо строк, то всё бы работало, так как тег в дочерних скоупах был бы таким же экземпляром, как и в book.tags, и изменение его значения (например, tag.name) просто работало бы, даже без двусторонней привязки.
Но предположим, что мы не хотим использовать здесь объекты.
Что делать в этом случае?
Неудачная попытка
- Я знаю! - ты можешь подумать.
– Я свяжу ng-repeat непосредственно со списком тегов восходящего потока! Давай попробуем: <div ng-controller="bookCtrl">
<div ng-repeat="tag in book.tags">
<input type="text" ng-model="book.tags[$index]">
</div>
</div>
Таким образом, связав ng-model напрямую с нужными элементами в списке тегов и не ссылаясь на дочернюю область, мы заставили наш код работать.
Почти.
Теперь значения внутри списка будут меняться по мере ввода текста.
Но теперь что-то другое не так.
Ты можешь посмотреть на себя .
Сделай это, я подожду.
Как видите, когда вы вводите символ, поле ввода теряет фокус.
Что за черт? Вините в этом ng-repeat. В целях эффективности ng-repeat отслеживает все значения в списке и перерисовывает отдельные элементы, которые изменились.
Но примитивы (например, числа и строки) в JavaScript неизменяемы.
Поэтому, если их необходимо изменить, предыдущий экземпляр выбрасывается и используется новый.
Таким образом, любое изменение примитива приводит к тому, что ng-repeat перерисовывает его.
В нашем случае это означает, что, избавляясь от старого и добавляя новое, мы попутно теряем фокус.
Решение
Нам нужно найти способ заставить ng-repeat идентифицировать элементы в списке независимо от их примитивного значения.Хорошим вариантом будет использование индекса примитива в списке.
Но как научить ng-repeat отслеживать элементы в списке?
К счастью для нас, в Angular 1.2 добавлено отслеживание по операторам: <div ng-controller="bookCtrl">
<div ng-repeat="tag in book.tags track by $index">
<input type="text" ng-model="book.tags[$index]">
</div>
</div>
Это решает нашу проблему, поскольку ng-repeat теперь использует индекс примитивов в списке вместе с самими примитивами.
Это означает, что ng-repeat больше не перерисовывает значения тега каждый раз, когда вы меняете его значение, поскольку его индекс остается прежним.
Ты можешь посмотреть на себя .
На самом деле, отслеживание гораздо полезнее для улучшить производительность приложений , но также полезно знать описанный выше обходной путь.
И, на мой взгляд, это поможет немного лучше понять магию Angular. Примечание переводчика: 29 мая в Москве состоится встреча , посвященный AngularJS, где также будет обсуждаться эта тема.
Теги: #разработка интерфейсов #разработка интерфейсов #angularjs #обходной путь #angular
-
Маховик
19 Oct, 24 -
Реализация Типов Объединения В Java
19 Oct, 24 -
Тонущий Корабль
19 Oct, 24 -
Сравнение Редакторов Wysiwyg 2007 Г.
19 Oct, 24