Как работает привязка данных в AngularJS?

1957

Как работает привязка данных в AngularJSрамках?

Я не нашел технических деталей на их сайте . Более или менее понятно, как это работает, когда данные распространяются от вида к модели. Но как AngularJS отслеживает изменения свойств модели без сеттеров и геттеров?

Я обнаружил, что есть наблюдатели JavaScript, которые могут выполнять эту работу. Но они не поддерживаются в Internet Explorer 6 и Internet Explorer 7 . Так как же AngularJS узнает, что я изменил, например, следующее и отразил это изменение в виде?

myobject.myproperty="new value";
Pashec
источник
10
Имейте в виду, что начиная с angular 1.0.0rc1 вам нужно указать ng-model-instant ( docs-next.angularjs.org/api/… ), чтобы ваш модер обновился безумно. В противном случае оно будет обновлено в случае размытия.
Сотомайор
8
Ссылка Марчелло явно не работает, и вот она снова: github.com/mhevery/angular.js/blob/master/docs/content/guide/…
riffraff
6
@orian, эта ссылка плохая. обновлено до (я полагаю) то же самое - docs.angularjs.org/guide/databinding
Кевин Мередит
11
Для тех, кто все еще читает этот вопрос, обратите внимание, что Angular 2.0 сильно изменил способ привязки данных со времени Angular 1.x для работы с веб-компонентами и решения многих вопросов в ответах ниже.
августа

Ответы:

2745

AngularJS запоминает значение и сравнивает его с предыдущим значением. Это основная грязная проверка. Если есть изменение в значении, то это вызывает событие изменения.

Вызывается $apply()метод, который вы называете, когда переходите из мира, отличного от AngularJS, в мир AngularJS $digest(). Дайджест - это просто старая грязная проверка. Он работает во всех браузерах и полностью предсказуем.

В отличие от грязной проверки (AngularJS) и слушателей изменений ( KnockoutJS и Backbone.js ): хотя грязная проверка может показаться простой и даже неэффективной (я расскажу об этом позже), оказывается, что она семантически верна все время, в то время как слушатели изменений имеют много странных угловых случаев и нуждаются в таких вещах, как отслеживание зависимостей, чтобы сделать его более семантически правильным. Отслеживание зависимостей KnockoutJS - это умная функция для проблемы, которой нет у AngularJS.

Проблемы со сменой слушателей:

  • Синтаксис ужасен, так как браузеры не поддерживают его изначально. Да, есть прокси, но они не являются семантически правильными во всех случаях, и, конечно, в старых браузерах нет прокси. Суть в том, что грязная проверка позволяет вам делать POJO , тогда как KnockoutJS и Backbone.js вынуждают вас наследовать от их классов и получать доступ к вашим данным через методы доступа.
  • Изменить коалесценцию. Предположим, у вас есть массив предметов. Скажем, вы хотите добавить элементы в массив, поскольку вы добавляете циклы, каждый раз, когда вы добавляете, вы запускаете события при изменении, то есть рендеринг пользовательского интерфейса. Это очень плохо для производительности. То, что вы хотите, это обновить пользовательский интерфейс только один раз, в конце. События изменения слишком детализированы.
  • Слушатели смены немедленно запускаются на установщике, что является проблемой, так как слушатель изменения может дополнительно изменять данные, что инициирует больше событий изменения. Это плохо, поскольку в вашем стеке может быть несколько событий изменений, происходящих одновременно. Предположим, у вас есть два массива, которые необходимо синхронизировать по любой причине. Вы можете добавлять только одно или другое, но каждый раз, когда вы добавляете, вы запускаете событие изменения, которое теперь имеет противоречивый взгляд на мир. Эта проблема очень похожа на блокировку потоков, которую JavaScript избегает, поскольку каждый обратный вызов выполняется исключительно и до завершения. События изменения прерывают это, поскольку сеттеры могут иметь далеко идущие последствия, которые не предназначены и неочевидны, что снова создает проблему потока. Оказывается, что вы хотите сделать, это отложить выполнение слушателя и гарантировать,

Как насчет производительности?

Так что может показаться, что мы медлительны, поскольку грязная проверка неэффективна. Здесь мы должны смотреть на реальные числа, а не просто иметь теоретические аргументы, но сначала давайте определим некоторые ограничения.

Люди это:

  • Медленно - все, что быстрее 50 мс, незаметно для человека и поэтому может рассматриваться как «мгновенное».

  • Ограниченный - Вы не можете действительно показать больше чем приблизительно 2000 частей информации человеку на одной странице. Что-то большее, чем это, действительно плохой пользовательский интерфейс, и люди все равно не смогут это обработать.

Таким образом, реальный вопрос заключается в следующем: сколько сравнений вы можете сделать в браузере за 50 мс? На этот вопрос сложно ответить, так как в игру вступают многие факторы, но вот контрольный пример: http://jsperf.com/angularjs-digest/6, который создает 10 000 наблюдателей. В современном браузере это занимает чуть менее 6 мс. В Internet Explorer 8 это занимает около 40 мс. Как видите, в наши дни это не проблема даже для медленных браузеров. Есть предостережение: сравнения должны быть простыми, чтобы соответствовать ограничению по времени ... К сожалению, слишком медленно добавлять медленное сравнение в AngularJS, поэтому легко создавать медленные приложения, когда вы не знаете, что вам нужно. делают. Но мы надеемся получить ответ, предоставив инструментальный модуль, который покажет вам, какие медленные сравнения.

Оказывается, что в видеоиграх и графических процессорах используется метод грязной проверки, особенно потому, что он последовательный. Пока они превышают частоту обновления монитора (обычно 50–60 Гц или каждые 16,6–20 мс), любая производительность, превышающая это, является пустой тратой, поэтому вам лучше рисовать больше материала, чем увеличивать FPS.

Миско Хевери
источник
32
@Mark - да, в KO вы просто добавляете .extend ({throttle: 500}), чтобы ждать 500 миллисекунд после последнего события изменения, прежде чем воздействовать на него.
Даниэль Уорвикер
158
Весь этот ответ великолепен, за исключением того, что «пока они получают 50 кадров в секунду, любая производительность сверх этого является пустой тратой, поскольку человеческий глаз не может это оценить, поэтому вам лучше рисовать больше материала, чем повышать число кадров в секунду». Это утверждение совершенно неверно в зависимости от вашего приложения. Глаз определенно может оценить более 50 кадров в секунду, и, как показывают различные проблемы с виртуальной реальностью (прочитайте любую из последних статей от Джона Кармака или Майкла Абраша, особенно выступление последнего на GDC 2013 VR), 50 кадров в секунду на самом деле слишком медленные. Кроме этого, ваш ответ великолепен. Я просто не хочу распространять дезинформацию.
Нейт Банди
10
@DavidRivers us - это мкс точно так же, как в utorrent 1 мкс = 0,000001 с
Торгейр
33
Это утверждение можно легко сказать в обратном порядке, так как «Грязная проверка - умная особенность для проблемы, которой нет нокаута». ES6 использует наблюдаемые, а Angular избавляется от грязной проверки. Реальный мир догнал этот ответ и показал, что он ложный.
коническая
17
«Все, что быстрее 50 мс, незаметно для людей» - это неправда. В ходе тестирования мы обнаружили, что наши клиенты могут легко различить задержку обновления 50 мс (20 кадров в секунду) и задержку обновления 16,6 мс (60 кадров в секунду). Сцены, движущиеся с прежней скоростью, последовательно получают худшие общие оценки «как это ощущалось», даже когда люди сознательно не регистрируют частоту кадров.
Crashworks
323

Миско уже дал отличное описание того, как работают привязки данных, но я хотел бы добавить свой взгляд на проблему производительности с привязкой данных.

Как сказал Миско, около 2000 привязок - это то место, где вы начинаете видеть проблемы, но в любом случае на странице не должно быть более 2000 фрагментов информации. Это может быть правдой, но не каждая привязка данных видна пользователю. Как только вы начнете создавать виджеты или сетки данных с двусторонним связыванием, вы можете легко выполнить 2000 привязок, не имея плохого UX.

Рассмотрим, например, поле со списком, в котором вы можете ввести текст для фильтрации доступных параметров. Этот вид контроля может иметь ~ 150 предметов и все еще быть очень полезным. Если у него есть какая-то дополнительная функция (например, определенный класс для текущей выбранной опции), вы начинаете получать 3-5 привязок для каждой опции. Разместите три из этих виджетов на странице (например, один для выбора страны, другой для выбора города в указанной стране и третий для выбора отеля), и вы уже находитесь в диапазоне от 1000 до 2000 привязок.

Или рассмотрите сетку данных в корпоративном веб-приложении. 50 строк на страницу не лишены смысла, каждая из которых может иметь 10-20 столбцов. Если вы построите это с помощью ng-повторов и / или будете иметь информацию в некоторых ячейках, в которых используются некоторые привязки, вы можете приблизиться к 2000 привязкам только с этой сеткой.

Я считаю, что это огромная проблема при работе с AngularJS, и единственное решение, которое мне удалось найти, - это создание виджетов без двустороннего связывания, вместо использования ngOnce, отмены регистрации наблюдателей и подобных трюков, или создание директивы, которые создают DOM с помощью jQuery и манипулирования DOM. Я чувствую, что это побеждает цель использования Angular в первую очередь.

Я хотел бы услышать предложения о других способах справиться с этим, но тогда, возможно, я должен написать свой собственный вопрос. Я хотел поместить это в комментарии, но это оказалось слишком длинным для этого ...

TL; DR
Привязка данных может вызвать проблемы производительности на сложных страницах.

МВт.
источник
26
Да, я второй. Основная ответственность нашего приложения заключается в отображении связей между различными объектами. На данной странице может быть 10 разделов. В каждом разделе есть таблица. Каждая таблица имеет 2-5 типовых фильтров. В каждой таблице 2-5 столбцов, в каждом по 10 строк. Очень быстро мы сталкиваемся с проблемами перфорирования и выбираем варианты «похожих трюков».
Скотт Сильви
10
Справедливо ли говорить, что Angular касается не только привязки данных, и некоторые приложения могут не захотеть использовать эту функцию именно по тем причинам, на которые ссылались другие? Я думаю, что подход DI и модульность сами по себе стоят многого; хорошо иметь магическое автоматическое связывание, но в каждой существующей реализации есть компромиссы производительности. Путь Angular, возможно, превосходит большинство веб-приложений CRUD, и люди просто бьют по стене, пытаясь довести ее до крайностей. Было бы неплохо иметь альтернативный метод прослушивания событий, но, может быть, он слишком сложен для одной платформы?
Джейсон Бойд
8
В Angular теперь есть возможность однонаправленной и однонаправленной привязки данных для решения этой проблемы. Кроме того, теперь он имеет индексы для вашего источника повторителя, что позволяет вам изменять список, не перестраивая dom для всего контента.
Gaute Løken
6
@MW. Честно говоря, я думал, что bind-Once был в ядре. Но, похоже, это не так. Это просто то, что вы можете сделать, когда пишете свои собственные директивы, в основном связывая вещи, не просматривая их. Тем не менее, есть мод для него: github.com/pasvaz/bindonce
Gaute Løken
9
Крики из будущего для любого, кто читает это: одноразовая привязка теперь является основной функцией Angular v1.3, читайте больше здесь: docs.angularjs.org/guide/expression
Nobita
158

Путем грязной проверки $scopeобъекта

Angular поддерживает простой arrayнаблюдателей в $scopeобъектах. Если вы проверите любой из них, $scopeвы обнаружите, что он содержит arrayвызываемый $$watchers.

Каждый наблюдатель - это objectто, что содержит среди прочего

  1. Выражение, за которым следит наблюдатель. Это может быть просто attributeимя или что-то более сложное.
  2. Последнее известное значение выражения. Это можно проверить по текущему вычисленному значению выражения. Если значения отличаются, наблюдатель запустит функцию и пометит $scopeкак грязную.
  3. Функция, которая будет выполнена, если наблюдатель загрязнен.

Как определяются наблюдатели

Есть много разных способов определения наблюдателя в AngularJS.

  • Вы можете явно на .$watchattribute$scope

    $scope.$watch('person.username', validateUnique);
  • Вы можете разместить {{}}интерполяцию в своем шаблоне (для вас будет создан наблюдатель на текущем $scope).

    <p>username: {{person.username}}</p>
  • Вы можете задать директиву, например, ng-modelопределить для вас наблюдателя.

    <input ng-model="person.username" />

$digestЦикл проверяет все наблюдатель против последнего значения

Когда мы взаимодействуем с AngularJS по обычным каналам (ng-модель, ng-repeat и т. Д.), Директива запускает цикл дайджеста.

Цикл дайджеста - это первый шаг$scope в глубину и всех его потомков . Для каждого $scope objectмы перебираем его $$watchers arrayи оцениваем все выражения. Если новое значение выражения отличается от последнего известного значения, вызывается функция наблюдателя. Эта функция может перекомпилировать часть DOM, повторно вычислить значение $scope, вызвать AJAX request, все, что вам нужно сделать.

Каждая область видимости прослеживается, и каждое выражение наблюдения оценивается и проверяется по последнему значению.

Если наблюдатель срабатывает, $scopeзначит он грязный

Если сработает наблюдатель, приложение узнает, что что-то изменилось, и $scopeпомечено как грязное.

Функции наблюдателя могут изменять другие атрибуты на $scopeили на родительском элементе $scope. Если одна $watcherфункция была запущена, мы не можем гарантировать, что наши другие $scopeвсе еще чисты, и поэтому мы снова выполняем весь цикл дайджеста.

Это связано с тем, что AngularJS имеет двустороннюю привязку, поэтому данные могут быть переданы обратно в $scopeдерево. Мы можем изменить значение на более высокое $scope, которое уже было переварено. Возможно, мы изменим значение на $rootScope.

Если $digestгрязный, мы $digestснова выполняем весь цикл

Мы непрерывно перебираем $digestцикл, пока либо цикл дайджеста не станет чистым (все $watchвыражения имеют то же значение, что и в предыдущем цикле), либо мы не достигнем предела дайджеста. По умолчанию этот предел установлен на 10.

Если мы достигнем предела дайджеста, AngularJS выдаст ошибку в консоли:

10 $digest() iterations reached. Aborting!

Дайджест сложен для машины, но легок для разработчика

Как вы можете видеть, каждый раз, когда что-то меняется в приложении AngularJS, AngularJS проверяет каждого наблюдателя в $scopeиерархии, чтобы увидеть, как реагировать. Для разработчика это огромный выигрыш в производительности, поскольку теперь вам практически не нужно писать код проводки, AngularJS просто заметит, изменилось ли значение, и сделает остальное приложение совместимым с этим изменением.

С точки зрения машины, хотя это крайне неэффективно и замедлит работу нашего приложения, если мы создадим слишком много наблюдателей. Миско привел цифру в 4000 зрителей, прежде чем ваше приложение будет работать медленнее в старых браузерах.

Этот предел легко достичь, если вы, например, ng-repeatболее чем большой JSON array. Вы можете избежать этого, используя такие функции, как одноразовая привязка для компиляции шаблона без создания наблюдателей.

Как избежать создания слишком большого количества наблюдателей

Каждый раз, когда ваш пользователь взаимодействует с вашим приложением, каждый наблюдатель в вашем приложении будет оцениваться как минимум один раз. Большая часть оптимизации приложения AngularJS - это уменьшение количества наблюдателей в вашем $scopeдереве. Один из простых способов сделать это - одноразовая привязка .

Если у вас есть данные, которые будут редко меняться, вы можете связать их только один раз, используя синтаксис ::, например:

<p>{{::person.username}}</p>

или

<p ng-bind="::person.username"></p>

Привязка будет срабатывать только тогда, когда содержащий шаблон визуализируется и данные загружаются в $scope.

Это особенно важно, когда у вас есть ng-repeatмного предметов.

<div ng-repeat="person in people track by username">
  {{::person.username}}
</div>
superluminary
источник
Спасибо @ user2864740 - хотя это правильно, что ответ Миско должен быть первым. Он знает фреймворк лучше, чем кто-либо другой, и это здорово, что он использует Stack Overflow ..
superluminary
4
Я не согласен с тем, что указанный ответ должен быть наверху; Существует разница между знанием чего-либо и написанием соответствующего / подробного ответа на конкретный вопрос. Есть лучшие способы получить похвалы. Во всяком случае ..
user2864740
1
Я не сомневаюсь, что это правда, но вопросы вопросы и ответы ответы :)
user2864740
3
Хороший ответ, рассказывающий о том, как ведет себя грязная проверка и что она на самом деле оценивает, в ответе Миско было не совсем ясно.
Strider
3
Превосходный и подробный ответ. @superluminary, спасибо за такой ответ. Более того, прочитав этот ответ, я пришел к выводу, что мы не должны добавлять неидемпотентное выражение в качестве наблюдаемого выражения.
Мангу Сингх Раджпурохит
81

Это мое основное понимание. Это может быть неправильно!

  1. Элементы отслеживаются путем передачи функции (возвращающей отслеживаемую вещь) $watchметоду.
  2. Изменения в отслеживаемых элементах должны быть внесены в блок кода, заключенный в $applyметод.
  3. В конце $applyв $digestвызове метода , который проходит через каждый из часов и проверяет , если они изменились с момента последнего $digestRAN.
  4. Если какие-либо изменения найдены, то дайджест вызывается снова, пока все изменения не стабилизируются.

В обычной разработке синтаксис привязки данных в HTML говорит компилятору AngularJS создать часы для вас, и методы контроллера уже запущены внутри $apply. Так что для разработчика приложений все прозрачно.

Пит Б.Д.
источник
4
когда применяется метод apply?
Numan Salati
3
@EliseuMonar Цикл дайджеста выполняется в результате какого-либо события или вызова $ apply (), он не вызывается периодически в зависимости от таймера. Посмотрите, как работает функция $ watch AngularJS? и как работает связывание и переваривание в AngularJS?
ADL
1
@remi, меня не волнует последняя версия AngularJS. Они уже используют прокси или Object.observe? Если нет, они все еще находятся в эпохе грязной проверки, которая строит синхронизированный цикл, чтобы увидеть, изменились ли атрибуты модели.
Eliseu Monar душ Сантуш
1
Я читал, что дайджест будет работать максимум десять раз sitepoint.com/understanding-angulars-apply-digest
user137717
62

Я задумался об этом сам некоторое время. Без сеттеров как AngularJSзаметить изменения $scopeобъекта? Это опрос их?

Что он на самом деле делает, так это: любое «нормальное» место, где вы модифицируете модель, уже AngularJSвызывается из кишок , поэтому оно автоматически вызывает $applyвас после выполнения кода. Скажем, у вашего контроллера есть метод, к которому подключен ng-clickкакой-то элемент. Поскольку вы AngularJSвызываете вызов этого метода для вас, у него есть шанс сделать это $applyв соответствующем месте. Аналогично, для выражений, которые отображаются прямо в представлениях, они выполняются AngularJSтак, что это делает $apply.

Когда в документации говорится о необходимости вызова $applyвручную для внешнегоAngularJS кода , речь идет о коде, который при запуске не вытекает из AngularJSсамого себя в стеке вызовов.

jpsimons
источник
32

Объясняя с картинками:

Привязка данных требует отображения

Ссылка в области не является точной ссылкой в ​​шаблоне. Когда вы связываете данные двух объектов, вам нужен третий, который слушает первый и модифицирует другой.

введите описание изображения здесь

Здесь, когда вы изменяете <input>, вы касаетесь data-ref3 . И классический механизм связывания данных изменит data-ref4 . Так как же {{data}}будут двигаться другие выражения?

События приводят к $ digest ()

введите описание изображения здесь

Angular поддерживает oldValueи newValueлюбой привязки. И после каждого события Angular знаменитый $digest()цикл будет проверять список наблюдения, чтобы увидеть, изменилось ли что-то. Эти угловые события являются ng-click, ng-change, $httpзавершено ... The $digest()цикл будет до тех пор , как любой oldValueотличается от newValue.

На предыдущем рисунке он заметит, что data-ref1 и data-ref2 изменились.

Выводы

Это немного похоже на яйцо и курицу. Вы никогда не знаете, кто начинает, но, надеюсь, это работает большую часть времени, как ожидалось.

Другое дело, что вы можете легко понять влияние простого связывания на память и процессор. Надеюсь, настольные компьютеры достаточно толстые, чтобы справиться с этим. Мобильные телефоны не так сильны.

Николас Зозол
источник
22

Очевидно, что нет периодической проверки того Scope, есть ли какие-либо изменения в объектах, прикрепленных к нему. Наблюдаются не все объекты, прикрепленные к области видимости. Область действия прототипа поддерживает $$ watchers . Scopeповторяется только $$watchersпри $digestвызове.

Angular добавляет наблюдателя в $$ watchers для каждого из этих

  1. {{expression}} - в ваших шаблонах (и везде, где есть выражение) или когда мы определяем ng-модель.
  2. $ scope. $ watch ('expression / function') - В вашем JavaScript мы можем просто прикрепить объект области видимости для angular для наблюдения.

Функция $ watch принимает три параметра:

  1. Первая - это функция-наблюдатель, которая просто возвращает объект, или мы можем просто добавить выражение.

  2. Вторая - это функция слушателя, которая будет вызываться при изменении объекта. Все вещи, такие как изменения DOM, будут реализованы в этой функции.

  3. Третий является необязательным параметром, который принимает логическое значение. Если это правда, Angular Deep наблюдает за объектом, а если его false, Angular просто наблюдает за объектом. Примерная реализация $ watch выглядит следующим образом

Scope.prototype.$watch = function(watchFn, listenerFn) {
   var watcher = {
       watchFn: watchFn,
       listenerFn: listenerFn || function() { },
       last: initWatchVal  // initWatchVal is typically undefined
   };
   this.$$watchers.push(watcher); // pushing the Watcher Object to Watchers  
};

В Angular есть интересная вещь, которая называется Digest Cycle. Цикл $ digest начинается в результате вызова $ scope. $ Digest (). Предположим, что вы изменили модель $ scope в функции-обработчике с помощью директивы ng-click. В этом случае AngularJS автоматически запускает цикл $ digest, вызывая $ digest (). Помимо ng-click, есть несколько других встроенных директив / сервисов, которые позволяют вам менять модели (например, ng-model, $ timeout и т. Д.) и автоматически запускает цикл $ digest. Примерная реализация $ digest выглядит следующим образом.

Scope.prototype.$digest = function() {
      var dirty;
      do {
          dirty = this.$$digestOnce();
      } while (dirty);
}
Scope.prototype.$$digestOnce = function() {
   var self = this;
   var newValue, oldValue, dirty;
   _.forEach(this.$$watchers, function(watcher) {
          newValue = watcher.watchFn(self);
          oldValue = watcher.last;   // It just remembers the last value for dirty checking
          if (newValue !== oldValue) { //Dirty checking of References 
   // For Deep checking the object , code of Value     
   // based checking of Object should be implemented here
             watcher.last = newValue;
             watcher.listenerFn(newValue,
                  (oldValue === initWatchVal ? newValue : oldValue),
                   self);
          dirty = true;
          }
     });
   return dirty;
 };

Если мы используем функцию setTimeout () в JavaScript для обновления модели области, Angular не сможет узнать, что вы можете изменить. В этом случае наша обязанность - вызвать $ apply () вручную, что запускает цикл $ digest. Аналогично, если у вас есть директива, которая устанавливает прослушиватель событий DOM и изменяет некоторые модели внутри функции-обработчика, вам нужно вызвать $ apply (), чтобы изменения вступили в силу. Основная идея $ apply заключается в том, что мы можем выполнить некоторый код, который не знает об Angular, этот код все еще может изменить вещи в области видимости. Если мы заключим этот код в $ apply, он позаботится о вызове $ digest (). Грубая реализация $ apply ().

Scope.prototype.$apply = function(expr) {
       try {
         return this.$eval(expr); //Evaluating code in the context of Scope
       } finally {
         this.$digest();
       }
};
Сасанк Сункавалли
источник
15

AngularJS обрабатывает механизм привязки данных с помощью трех мощных функций: $ watch () , $ digest () и $ apply () . В большинстве случаев AngularJS будет вызывать $ scope. $ Watch () и $ scope. $ Digest (), но в некоторых случаях вам, возможно, придется вызывать эти функции вручную для обновления с новыми значениями.

$ watch () : -

Эта функция используется для наблюдения за изменениями в переменной $ scope. Он принимает три параметра: выражение, слушатель и объект равенства, где слушатель и объект равенства являются необязательными параметрами.

$ digest () -

Эта функция перебирает все часы в объекте $ scope и его дочерних объектах $ scope
(если есть). Когда $ digest () выполняет итерацию по наблюдениям, он проверяет, изменилось ли значение выражения. Если значение изменилось, AngularJS вызывает слушателя с новым значением и старым значением. Функция $ digest () вызывается всякий раз, когда AngularJS считает это необходимым. Например, после нажатия кнопки или после вызова AJAX. У вас могут быть случаи, когда AngularJS не вызывает функцию $ digest () для вас. В этом случае вы должны назвать это сами.

$ apply () -

Angular автоматически обновляет только те изменения модели, которые находятся в контексте AngularJS. Когда вы изменяете любую модель вне контекста Angular (например, события DOM браузера, setTimeout, XHR или сторонние библиотеки), вам необходимо сообщить Angular об изменениях, вызвав $ apply () вручную. Когда вызов функции $ apply () завершается, AngularJS вызывает внутреннюю функцию $ digest (), поэтому все привязки данных обновляются.

Бхарат Кумар
источник
7

Случилось так, что мне нужно было связать модель данных человека с формой, и я сделал прямое сопоставление данных с формой.

Например, если модель имела что-то вроде:

$scope.model.people.name

Контрольный ввод формы:

<input type="text" name="namePeople" model="model.people.name">

Таким образом, если вы измените значение контроллера объекта, оно будет автоматически отражено в представлении.

Пример, в котором я передал модель, обновляется из данных сервера, когда вы запрашиваете почтовый индекс и почтовый индекс, основанный на письменной загрузке списка колоний и городов, связанных с этим представлением, и по умолчанию задаете первое значение для пользователя. И я работал очень хорошо, что происходит, angularJSиногда требуется несколько секунд, чтобы обновить модель, для этого вы можете поставить счетчик во время отображения данных.

gartox
источник
14
Я прочитал этот ответ 5 раз, и я до сих пор не понимаю, что здесь имеется в виду.
сбулин
1
Ответ кажется мне загадкой
Аман
6
  1. Одностороннее связывание данных - это подход, при котором значение берется из модели данных и вставляется в элемент HTML. Нет способа обновить модель из вида. Используется в классических шаблонных системах. Эти системы связывают данные только в одном направлении.

  2. Привязка данных в приложениях Angular - это автоматическая синхронизация данных между компонентами модели и вида.

Привязка данных позволяет вам рассматривать модель как единый источник истины в вашем приложении. Представление является проекцией модели во все времена. Если модель изменяется, представление отражает это изменение и наоборот.

Шанкар Гангадхар
источник
5

Вот пример привязки данных с AngularJS, используя поле ввода. Позже объясню

HTML-код

<div ng-app="myApp" ng-controller="myCtrl" class="formInput">
     <input type="text" ng-model="watchInput" Placeholder="type something"/>
     <p>{{watchInput}}</p> 
</div>

Код AngularJS

myApp = angular.module ("myApp", []);
myApp.controller("myCtrl", ["$scope", function($scope){
  //Your Controller code goes here
}]);

Как видно из приведенного выше примера, AngularJS использует ng-modelдля прослушивания и просмотра того, что происходит с элементами HTML, особенно с inputполями. Когда что-то случится, сделай что-нибудь. В нашем случае, ng-modelэто привязка к нашему мнению, используя обозначение усов {{}}. Все, что введено в поле ввода, отображается на экране мгновенно. И в этом прелесть связывания данных, используя AngularJS в его простейшей форме.

Надеюсь это поможет.

Смотрите рабочий пример здесь на Codepen

AllJs
источник
5

AngularJs поддерживает двухстороннюю привязку данных .
Означает, что вы можете получить доступ к данным View -> Controller & Controller -> View

Например

1)

// If $scope have some value in Controller. 
$scope.name = "Peter";

// HTML
<div> {{ name }} </div>

O / P

Peter

Вы можете связать данные в ng-modelLike: -
2)

<input ng-model="name" />

<div> {{ name }} </div>

Вот в приведенном выше примере, что бы ни вводил пользователь ввода, это будет видно в <div>теге.

Если вы хотите привязать ввод из html к контроллеру: -
3)

<form name="myForm" ng-submit="registration()">
   <label> Name </lbel>
   <input ng-model="name" />
</form>

Здесь, если вы хотите использовать вход nameв контроллере, то,

$scope.name = {};

$scope.registration = function() {
   console.log("You will get the name here ", $scope.name);
};

ng-modelсвязывает наш взгляд и представляет его в выражении {{ }}.
ng-modelэто данные, которые отображаются пользователю в представлении и с которыми взаимодействует пользователь.
Так что легко связать данные в AngularJs.

одж кулкарни
источник
4

Angular.js создает наблюдатель для каждой модели, которую мы создаем. Всякий раз, когда модель изменяется, к модели добавляется класс «ng-dirty», поэтому наблюдатель будет наблюдать за всеми моделями, имеющими класс «ng-dirty», и обновлять их значения в контроллере и наоборот.

Шанкар Гангадхар
источник
3

привязка данных:

Что такое привязка данных?

Всякий раз, когда пользователь изменяет данные в представлении, происходит обновление этого изменения в модели области действия, и наоборот.

Как это возможно?

Краткий ответ: с помощью цикла дайджеста.

Описание: Angular js устанавливает наблюдателя на модель объема, которая запускает функцию слушателя, если в модели есть изменение.

$scope.$watch('modelVar' , function(newValue,oldValue){

// Dom обновляет код новым значением

});

Так когда и как вызывается функция наблюдателя?

Функция наблюдателя вызывается как часть цикла дайджеста.

Цикл дайджеста вызывается автоматически, как часть угловых js, встроенных в директивы / сервисы, такие как ng-model, ng-bind, $ timeout, ng-click и другие ..., которые позволяют запустить цикл дайджеста.

Функция цикла дайджеста:

$scope.$digest() -> digest cycle against the current scope.
$scope.$apply() -> digest cycle against the parent scope 

т.е.$rootScope.$apply()

Примечание: $ apply () равно $ rootScope. $ Digest () это означает, что грязная проверка начинается прямо с корня или вершины или родительской области видимости для всех дочерних областей $ в угловом приложении js.

Вышеперечисленные функции работают в браузере IE для упомянутых версий, также просто убедившись, что ваше приложение является приложением angular js, что означает, что вы используете файл сценария фреймворка angularjs, указанный в теге script.

Спасибо.

Dhana
источник