Магия Angularjs: Никогда Не Устанавливайте Привязки К Примитивам



Магия 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

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.