Як я можу використовувати $ range. $ Watch і $ range. $ Застосувати в AngularJS?


1088

Я не розумію, як користуватися $scope.$watchта $scope.$apply. Офіційна документація не корисна.

Чого я конкретно не розумію:

  • Вони підключені до DOM?
  • Як я можу оновити зміни DOM до моделі?
  • Яка точка зв’язку між ними?

Я спробував цей підручник , але це сприймає розуміння $watchі $applyяк належне.

Що робити $applyі $watchробити, і як я їх правильно використовувати?

Відповіді:


1737

Вам потрібно знати, як працює AngularJS, щоб зрозуміти це.

Дайджест циклу і $ сфера

Перш за все, AngularJS визначає концепцію так званого дайджест-циклу . Цей цикл можна розглядати як цикл, під час якого AngularJS перевіряє, чи є якісь зміни всіх змінних, які спостерігаються всіма $scopes. Отже, якщо ви $scope.myVarвизначили у своєму контролері і ця змінна була позначена як переглянута , ви неявно говорите AngularJS стежити за змінами myVarв кожній ітерації циклу.

Природним наступним запитанням було б: чи все пов'язане з $scopeпереглядом? На щастя, ні. Якщо ви будете спостерігати за змінами кожного об'єкту у вашому $scope, то швидко оцінювальний цикл потребуватиме вікових оцінок, і ви швидко зіткнетеся з проблемами продуктивності. Ось чому команда AngularJS дала нам два способи оголошення певної $scopeзмінної як переглянутої (читайте нижче).

$ watch допомагає слухати зміни в обсязі $

Є два способи оголошення $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 дозволяє інтегрувати зміни в цикл дайджесту

Ви можете думати про $applyфункцію як про механізм інтеграції . Розумієте, щоразу, коли ви змінюєте якусь переглянуту змінну, прикріплену до$scope об'єкта безпосередньо, AngularJS буде знати, що зміни відбулися. Це тому, що AngularJS вже знав, щоб контролювати ці зміни. Отже, якщо це трапиться в коді, яким керує фреймворк, цикл дайджесту продовжиться.

Однак іноді потрібно змінити якесь значення поза світом AngularJS і побачити, як зміни поширюються нормально. Враховуйте це - у вас є $scope.myVarзначення, яке буде змінено в $.ajax()обробнику jQuery . Це станеться в якийсь момент в майбутньому. AngularJS не може чекати, коли це станеться, оскільки його не отримали інструкції чекати на jQuery.

Для вирішення цього питання $applyбуло введено. Це дозволяє чітко запустити цикл травлення. Однак вам слід використовувати це лише для міграції деяких даних до AngularJS (інтеграція з іншими рамками), але ніколи не використовуйте цей метод у поєднанні з регулярним кодом AngularJS, оскільки AngularJS видасть помилку.

Як все це пов'язане з DOM?

Що ж, вам слід справді повторити підручник ще раз, коли ви все це знаєте. Цикл дайджесту забезпечить синхронізацію користувальницького інтерфейсу та коду JavaScript, оцінивши кожного спостерігача, приєднаного до всіх $scopes, доки нічого не зміниться. Якщо в циклі дайджесту більше не відбудеться змін, він вважається закінченим.

Ви можете приєднати об'єкти до $scopeоб'єкта або явно в Контролері, або оголосивши їх у {{expression}}формі безпосередньо у поданні.

Я сподіваюся, що це допоможе з’ясувати деякі основні знання про все це.

Подальші читання:


57
"Кутова перевірка, чи є якісь зміни у всіх змінних, приєднаних до всіх областей $" - я не думаю, що це цілком правильно. Я вважаю, що Angular (брудно) перевіряє властивості $ range, у яких було встановлено $ годинник (зауважте, що використання {{}} у представленні автоматично створить $ watch). Дивіться також розділ "Область застосування $ дивіться ефективність роботи" на сторінці сфери застосування .
Марк Райкок

5
Це може бути так. Я спробую знайти якийсь час, щоб прочитати більше про це і відредагувати свою відповідь.
ŁukaszBachman

15
@MarkRajcok, ти мав рацію. Я змінив свою відповідь і вказав на статтю, яка добре показує, як це здійснюється.
ŁukaszBachman

3
як щодо використання цього? (Метод «Контроль як»)
Леандро

2
Використання "Управління як" не повинно впливати на інформацію вище. Використовуючи this.myVar ставить myVar на область застосування.
Маркус Роделл

161

У AngularJS ми оновлюємо наші моделі, а наші погляди / шаблони оновлюють DOM "автоматично" (за допомогою вбудованих або спеціальних директив).

$ apply і $ watch, обидва методи обстеження, не пов'язані з DOM.

На сторінці Концепції (розділ "Час виконання") є досить добре пояснення циклу дайджестів $, $ apply, черги $ evalAsync та списку перегляду $. Ось малюнок, який супроводжує текст:

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

Який би код не мав доступ до області застосування - зазвичай контролери та директиви (їх функції зв’язку та / або їх контролери) - можуть створити " watchExpression ", який AngularJS оцінить відповідно до цієї сфери. Ця оцінка відбувається щоразу, коли AngularJS вводить цикл перетворення $ (зокрема, цикл "$ watch list"). Ви можете переглядати окремі властивості області, ви можете визначити функцію для перегляду двох властивостей разом, ви можете спостерігати довжину масиву тощо.

Коли все відбувається "всередині AngularJS" - наприклад, ви вводите в текстове поле, у якому ввімкнено двостороння прив'язка даних AngularJS (тобто використовується ng-модель), спрацьовує зворотний виклик $ http тощо. - $ application вже зателефоновано, тому ми знаходиться у прямокутнику "AngularJS" на малюнку вище. Будуть оцінені всі watchExpressions (можливо, більше одного разу - поки не будуть виявлені подальші зміни).

Коли все відбувається "за межами AngularJS" - наприклад, ви використовували bind () у директиві, а потім спрацьовує подія, що призводить до виклику зворотного дзвінка, або деяких пожеж, зареєстрованих у jQuery, - ми все ще знаходимося в прямокутнику "Native". Якщо код зворотного виклику модифікує будь-що, що переглядає будь-який годинник $, зателефонуйте $ apply, щоб потрапити в прямокутник AngularJS, викликаючи цикл дайджесту $, і, отже, AngularJS помітить зміни та зробить свою магію.


5
Я розумію ідею, що я не розумію - це те, як фактично передаються дані. У мене є модель, яка є об’єктом з великою кількістю даних, я використовую деякі з них для управління DOM. то частина цього змінюється. Як розмістити змінені дані в потрібному місці в моделі? У прикладі, який я використав, він робить маніпуляції, і врешті-решт просто використовує scope.$apply(scope.model), я не розумію, які дані передаються та як вони передаються в потрібне місце в моделі?
ilyo

6
Ніякої магічної передачі даних не відбувається. Зазвичай у програмах Angular вам слід змінити кутові моделі, які потім керують оновленнями перегляду / DOM. Якщо ви оновите DOM за межами Angular, вам доведеться оновити моделі вручну. scope.$apply(scope.model)просто оцінить scope.modelяк кутовий вираз, а потім введе цикл дайджестів $. У статті, на яку ви посилаєтесь, ймовірно, scope.$apply()це буде достатньо, оскільки модель вже зараз $ watch'ed. Функція stop () - це оновлення моделі (я вважаю, що toUpdate - це посилання на obseg.model), і тоді викликається $ apply.
Марк Райкок

Схоже, документи AngularJS змістилися з-під цієї відповіді (у першого посилання немає "часу виконання" чи $watchна сторінці, а друге посилання розірвано - як і раніше). Болісно, архівні версії не кешували будь-який процес асинхронізації, який створював вміст.
ruffin

52

AngularJS розширює цей цикл подій , створюючи щось, що називається AngularJS context.

$ watch ()

Кожен раз , коли ви що - то зв'язати в інтерфейсі ви вставити $watchв $watchсписок .

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

Ось ми маємо $scope.user, який пов'язаний з першим входом, і маємо $scope.pass, який пов'язаний з другим. Роблячи це, ми додаємо два списки $watchдо $watchсписку .

Коли наш шаблон завантажується, AKA у фазі зв’язування, компілятор шукатиме кожну директиву та створює всі $watchнеобхідні програми.

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

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

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. $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 не створює жодного годинника.

Натискаємо кнопку.

  1. Браузер отримує подію, яка увійде в контекст AngularJS
  2. $digestЦикл буде працювати і буде просити кожен $ спостерігати за змінами.
  3. Оскільки те, $watchщо спостерігало за змінами в $ range.name, повідомляє про зміну, воно змусить іншого $digestциклу.
  4. Новий цикл нічого не повідомляє.
  5. Веб-переглядач повертає керування і оновить DOM, відображаючи нове значення $ range.name
  6. Тут важливим є те, що КОЖНА подія, яка входить у контекст AngularJS, запустить $digestцикл. Це означає, що кожного разу, коли ми пишемо лист у вигляді вводу, цикл буде виконувати перевірку кожного $watchна цій сторінці.

$ apply ()

Якщо ви зателефонуєте, $applyколи подія запускається, вона пройде через кутовий контекст, але якщо ви її не зателефонуєте, вона запуститься поза нею. Це так просто, як це. $applyбуде викликати$digest() цикл внутрішньо, і він повторить усі годинники, щоб переконатися, що DOM оновлюється за допомогою оновленого значення.

$apply()Метод викликатиме спостерігач по всій $scopeланцюга , тоді як $digest()метод буде тільки викликати спостерігач на поточному $scopeта її children. Коли жодному з вищих $scopeоб'єктів не потрібно знати про локальні зміни, ви можете використовувати $digest().


18

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

Далі наведено кілька слайдів, які використовуються у цих відео для пояснення понять (про всяк випадок, якщо вищезазначені посилання видалено / не працюють).

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

У наведеному вище зображенні "$ range.c" не спостерігається, оскільки він не використовується в жодному з прив'язок даних (у розмітці). Інші два ( $scope.aі $scope.b) будуть переглянуті.

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

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

Більше про $applyта $digest:

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


17

Є $watchGroupі $watchCollectionтак само. Зокрема, $watchGroupдуже корисно, якщо ви хочете викликати функцію для оновлення об'єкта, який має декілька властивостей у представленні, яке не є об'єктом dom, наприклад, інший вигляд у полотні, WebGL або запиті сервера.

Тут посилання на документацію .


Я б прокоментував це, $watchCollectionале, я бачу, ви вже це зробили. Ось документація про це з сайту AngularJS. Вони забезпечують дуже приємну візуальну $watchглибину. Зверніть увагу, що інформація знаходиться внизу сторінки.
JabberwockyDecompiler

15

Просто закінчіть читати ВСЕ вище сказане, нудно і сонливо (вибачте, але це правда). Дуже технічна, поглиблена, детальна та суха. Чому я пишу? Оскільки AngularJS є масовим, безліч взаємопов'язаних концепцій може перетворити будь-кого. Я часто запитував себе, чи я не досить розумний, щоб їх зрозуміти? Ні! Це тому, що так мало хто може пояснити технологію на думмі-мові без усіх термінологій! Гаразд, спробуйте:

1) Усі вони керовані подіями. (Я чую сміх, але читаю далі)

Якщо ви не знаєте, що таке події, то подумайте, що ви розміщуєте кнопку на сторінці, підключаєте її до функції за допомогою "натискання на клік", чекаючи, коли користувачі натиснуть на неї, щоб викликати дії, які ви запускаєте всередині функція. Або подумайте про "тригер" SQL Server / Oracle.

2) $ watch - це "натискання".

Особливістю є те, що вона приймає 2 функції як параметри, перша дає значення події, друга - враховує значення ...

3) $ digest - це бос, який невтомно перевіряє , бла-бла-бла, але хороший начальник.

4) $ apply дає вам спосіб, коли ви хочете зробити це вручну , як відмову (якщо натискання не натисне, ви змусите його запустити.)

Тепер давайте зробимо це візуально. Зобразіть це, щоб зробити його ідеєю ще простіше:

В ресторані,

- ОФІТИ

повинні приймати замовлення у клієнтів, це

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

- МЕНЕДЖЕР, що біжить навколо, щоб переконатися, що всі офіціанти прокинулися, реагуючи на будь-які ознаки змін від клієнтів. Це є$digest()

- Власник має надзвичайну силу керувати всім на прохання, це так$apply()


2
Це може зрозуміти 5-річний. Я ціную таку відповідь. +1
Chris22
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.