Как использовать $scope.$ watch и $scope.$применить в AngularJS?

Я не понимаю, как использовать $scope.$watch и $scope.$apply. Официальная документация не помогает.

чего я не понимаю конкретно:

  • они связаны с DOM?
  • как я могу обновить изменения DOM в модели?
  • какова точка связи между ними?

пробовал в этом уроке, но это требует понимания $watch и $apply для предоставленный.

что делать $apply и $watch do, и как я могу использовать их соответствующим образом?

7 ответов


вы должны знать о том, как AngularJS работает, чтобы понять его.

цикл дайджеста и $ scope

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

естественным последующим вопросом было бы: все ли связано с $scope следят? К счастью, нет. Если бы вы следили за изменениями каждого объекта в вашем $scope, затем быстро цикл дайджеста займет века, чтобы оценить, и вы быстро столкнетесь с проблемами производительности. Вот почему команда AngularJS дала нам два способа объявить некоторые $scope переменная как наблюдаемая (читайте ниже).

$watch помогает прослушивать изменения $ scope

существует два способа объявления $scope переменной, как следят.

  1. используя его в своем шаблоне через выражение <span>{{myVar}}</span>
  2. , добавив его вручную через $watch сервис

1 объявлений) Это самый распространенный сценарий, и я уверен, что вы видели его раньше, но вы не знали, что это создало смотрите на заднем плане. Да, было! Использование директив AngularJS (например,ng-repeat) также можно создавать неявные часы.

2 объявлений) Вот как вы создаете свой собственный часы. $watch сервис поможет вам запустить некоторый код, когда какое-то значение прикреплено к $scope изменилось. Он редко используется, но иногда помогает. Например, если вы хотите запускать некоторый код каждый раз, когда изменяется "myVar", вы можете сделать следующее:

function MyController($scope) {

    $scope.myVar = 1;

    $scope.$watch('myVar', function() {
        alert('hey, myVar has changed!');
    });

    $scope.buttonClicked = function() {
        $scope.myVar = 2; // This will trigger $watch expression to kick in
    };
}

$apply позволяет интеграция изменений с циклом digest

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

, иногда вы хотите измените некоторое значение за пределами мира AngularJS и увидеть, как изменения распространяются нормально. Подумайте об этом - у вас есть $scope.myVar значение, которое будет изменено в jQuery $.ajax() обработчик. Это произойдет в какой-то момент в будущем. AngularJS не может дождаться этого, так как ему не было поручено ждать jQuery.

чтобы справиться с этим,$apply была введена. Это позволяет начать цикл пищеварения явно. Однако, вы должны только используйте это для переноса некоторых данных в AngularJS (интеграция с другими фреймворками), но никогда не используйте этот метод в сочетании с обычным кодом AngularJS, так как AngularJS выдаст ошибку.

как все это связано с DOM?

Ну, вы должны действительно следовать учебник снова, теперь, когда вы знаете все это. Цикл дайджеста обеспечит синхронизацию пользовательского интерфейса и кода JavaScript, оценив каждый наблюдатель, прикрепленный ко всем $scopes до тех пор, пока ничего изменения. Если в цикле дайджеста больше не происходит изменений, то он считается законченным.

вы можете прикрепить объекты к $scope объект либо явно в контроллере, либо путем объявления их в {{expression}} форма непосредственно в представлении.

я надеюсь, что помогает прояснить некоторые базовые знания обо всем этом.

дополнительные материалы:


в AngularJS мы обновляем наши модели, а наши представления/шаблоны обновляют DOM "автоматически" (через встроенные или пользовательские директивы).

$apply и $watch, оба метода области, не связаны с DOM.

на концепции страница (раздел "время выполнения") имеет довольно хорошее объяснение цикла $digest, $apply, очереди $evalAsync и списка $watch. Вот изображение, которое сопровождает текст:

$digest loop

все код имеет доступ к области-обычно контроллеры и директивы (их функции связи и / или их контроллеры) – могут настроить "watchExpression " это AngularJS будет оценивать против этой области. Эта оценка происходит всякий раз, когда AngularJS входит в цикл $digest (в частности, цикл "$watch list"). Вы можете наблюдать отдельные свойства области, вы можете определить функцию для просмотра двух свойств вместе,вы можете наблюдать длину массива и т. д.

когда все произойдет "внутри AngularJS" -например, вы вводите в текстовое поле, которое имеет двустороннюю привязку данных AngularJS (т. е. использует ng-модель), обратный вызов $http и т. д. - $apply уже вызван, поэтому мы находимся внутри прямоугольника "AngularJS" на рисунке выше. Все watchExpressions будут оценены (возможно, более одного раза-до тех пор, пока не будут обнаружены дальнейшие изменения).

когда что-то происходит "вне AngularJS" - например, вы использовали bind() в директиве, а затем это событие срабатывает, в результате чего ваш обратный вызов вызывается или некоторые зарегистрированные jQuery обратные вызовы-мы все еще находимся в" родном " прямоугольнике. Если код обратного вызова изменяет все, что смотрит любой $ watch, вызовите $apply, чтобы попасть в прямоугольник AngularJS, заставляя цикл $digest работать, и, следовательно, AngularJS заметит изменение и сделает свою магию.


этот блог было охвачено все, что создает примеры и понятные объяснения.

В В AngularJS $scope функции $watch(), $digest() и $apply() некоторые из центральных функций в AngularJS. Понимание $watch(), $digest() и $apply() имеет важное значение для того, чтобы понять AngularJS.

когда вы создаете привязку данных откуда-то в своем представлении к переменной на объекте $scope, AngularJS создает "часы" внутри. Часы означает, что AngularJS наблюдает за изменениями переменной на $scope object. Фреймворк "наблюдает" за переменной. Часы создаются с помощью $scope.$watch() функция, которую я рассмотрю позже в этом тексте.

в ключевых точках вашего приложения AngularJS вызывает


AngularJS расширяет это события-loop, создание чего-то под названием AngularJS context.

$watch ()

каждый раз, когда вы связываете что-то в пользовательском интерфейсе, вы вставляете $watch на $watch список.

User: <input type="text" ng-model="user" />
Password: <input type="password" ng-model="pass" />

здесь мы имеем $scope.user, который привязан к первому входу, и у нас есть $scope.pass, который привязан ко второму. Делая это, мы добавляем два $watches к $watch список.

когда наши шаблон загружается, АКА в фазе связывания, компилятор будет искать каждую директиву и создает все $watches, которые необходимы.

AngularJS обеспечивает $watch, $watchcollection и $watch(true). Ниже приведена аккуратная диаграмма, объясняющая все три взятые из наблюдателей глубина.

Enter image description here

angular.module('MY_APP', []).controller('MyCtrl', MyCtrl)
function MyCtrl($scope,$timeout) {
  $scope.users = [{"name": "vinoth"},{"name":"yusuf"},{"name":"rajini"}];

  $scope.$watch("users", function() {
    console.log("**** reference checkers $watch ****")
  });

  $scope.$watchCollection("users", function() {
    console.log("**** Collection  checkers $watchCollection ****")
  });

  $scope.$watch("users", function() {
    console.log("**** equality checkers with $watch(true) ****")
  }, true);

  $timeout(function(){
     console.log("Triggers All ")
     $scope.users = [];
     $scope.$digest();

     console.log("Triggers $watchCollection and $watch(true)")
     $scope.users.push({ name: 'Thalaivar'});
     $scope.$digest();

     console.log("Triggers $watch(true)")
     $scope.users[0].name = 'Superstar';
     $scope.$digest();
  });
}

http://jsfiddle.net/2Lyn0Lkb/

$digest цикл

когда браузер получает событие, которое может управляться контекстом AngularJS $digest цикл будет уволен. Эта петля состоит из двух меньших петель. Один обрабатывает $evalAsync очередь, а другой обрабатывает $watch list. The $digest будет петля через список $watch что мы есть

app.controller('MainCtrl', function() {
  $scope.name = "vinoth";

  $scope.changeFoo = function() {
      $scope.name = "Thalaivar";
  }
});

{{ name }}
<button ng-click="changeFoo()">Change the name</button>

здесь у нас только один $watch потому что ng-click не создает никаких часов.

нажимаем кнопку.

  1. браузер получает событие, которое войдет в контекст AngularJS
  2. на $digest цикл будет работать и будет запрашивать каждые $watch для изменений.
  3. с $watch, который наблюдал за изменениями в $охвата.название сообщает об изменении, это заставит другого $digest петли.
  4. новый петля ничего не сообщает.
  5. браузер возвращает элемент управления, и он обновит DOM отражение нового значения $ scope.имя
  6. важно то, что каждое событие, которое входит в контекст AngularJS, будет запускать $digest петли. Это означает, что каждый раз, когда мы пишем письмо на входе, цикл будет запускать проверку каждого $watch в этой странице.

$apply ()

если вы называете $apply когда событие уволено, оно пойдет через угловой контекст, но если вы его не назовете, он будет работать вне его. Это так просто. $apply будем называть $digest() цикл внутри, и он будет повторяться по всем часам, чтобы гарантировать, что DOM обновляется с недавно обновленным значением.

на $apply() метод вызовет наблюдателей на весь $scope цепи а $digest() метод будет вызывать только наблюдателей на текущем $scope и children. когда ни один из выше $scope объекты должны знать о локальных изменениях, вы можете использовать $digest().


здесь $watchGroup и $watchCollection Как хорошо. В частности, $watchGroup действительно полезно, если вы хотите вызвать функцию для обновления объекта, который имеет несколько свойств в представлении, которое не является объектом dom, например, другое представление в canvas, webGL или Server request. Вот, документация ссылке.


Я нашел очень глубокие видео, которые охватывают $watch, $apply, $digest и дайджест циклов в:

Ниже приведены несколько слайдов, используемых в этих видео, чтобы объяснить концепции (на всякий случай, если вышеуказанные ссылки удалены/не работают).

Enter image description here

на приведенном выше изображении " $ scope.c " не отслеживается, поскольку он не используется ни в одной из Привязок данных (в разметке). Двое других ($scope.a и $scope.b) будет смотрели.

Enter image description here

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

подробнее о $apply и $digest:

Enter image description here


просто закончите читать все выше, скучно и сонно (извините, но это правда). Очень технический, глубокий, подробный и сухой. Зачем я пишу? Поскольку AngularJS массивен, множество взаимосвязанных концепций может свести с ума любого. Я часто спрашивал себя: неужели я недостаточно умен, чтобы понять их? Нет! Это потому, что так мало может объяснить технологию в для dummie язык без всех терминологий! Ладно, попробую:

1) все они управляются событиями вещи. (Я слышу смех, но читайте дальше)

Если вы не знаете, что такое event-driven, то думаю, вы поместите кнопку на странице подключите его с помощью функции "on-click", ожидая пользователи нажимают на него, чтобы вызвать действия, которые вы устанавливаете внутри функция. Или подумайте о "триггере" SQL Server / Oracle.

2) $ watch - это "on-click".

что особенного в том, что он принимает 2 функции как параметры, первый дает значение из события, Второй принимает значение в рассмотрение...

3) $digest-это босс, который неустанно проверяет, бла-бла-бла, но хороший босс.

4) $apply дает вам способ, когда вы хотите сделать это вручную, как отказоустойчивый (в случае, если on-click не срабатывает, вы заставляете его работать.)

теперь давайте сделаем его визуально. Представь это, чтобы было еще проще. схватите идею:

в ресторане

- официанты должны принимать заказы от клиентов, это

$watch(
  function(){return orders;},
  function(){Kitchen make it;}
);

- руководителя бегать вокруг, чтобы убедиться, что все официанты проснулись, реагируют на любые признаки изменений от клиентов. Это $digest()

- собственником имеет максимальную власть, чтобы управлять всеми по запросу, это $apply()