AngularJS: автоматически обнаруживать изменение модели

103

Предположим, я хотел сделать что-то вроде автоматического запуска некоторого кода (например, сохранения данных на сервер) при изменении значений модели. Есть ли единственный способ сделать это, установив что-то подобное ng-changeдля каждого элемента управления, который мог бы изменить модель?

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

myModel.on('change', function() {
  $.post("/my-url", ...);
});

как вы могли бы видеть с чем-то вроде позвоночника.

Алек
источник

Ответы:

151

В представлениях с {{}}и / или ng-моделью Angular настраивает $watch()es за вас за кулисами.

По умолчанию $watchсравнивает по ссылке. Если установить третий параметр $watchв true, Угловой будет вместо «мелкого» наблюдать объект для изменения. Для массивов это означает сравнение элементов массива, для карт объектов это означает просмотр свойств. Итак, это должно делать то, что вы хотите:

$scope.$watch('myModel', function() { ... }, true);

Обновление : Angular v1.2 добавил новый метод для этого, `$ watchCollection () :

$scope.$watchCollection('myModel', function() { ... });

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

Марк Райкок
источник
1
Ах, отлично! Есть ли какая-то причина, по которой это, похоже, не все, что задокументировано (т.е. я не думаю, что ни один из руководств на сайте angular упоминал прямую настройку $ watch)? Есть ли в этом что-то плохое, что сделало бы установку (потенциально нескольких) ng-changeхуков на элементах управления вводом лучшей идеей?
Alec
12
Да, было бы неплохо, если бы в основном руководстве где-то упоминались $ watch. Что "плохо" в этом подходе, так это то, что он может занять много времени, если ваша модель большая (каждый цикл дайджеста - каждое нажатие клавиши в поле ввода - приведет к тому, что эта модель будет подвергаться глубокой грязной проверке, возможно, несколько раз) . В этом случае было бы лучше использовать выборочные $ watch () es или выборочные ng-change.
Марк Райкок
8

И если вам нужно динамически стилизовать элементы формы в соответствии с их состоянием (изменено / не изменено) или проверить, действительно ли изменились некоторые значения, вы можете использовать следующий модуль, разработанный мной: https://github.com/betsol / угловой-ввод-изменен

Он добавляет к форме и ее дочерним элементам дополнительные свойства и методы. С его помощью вы можете проверить, содержит ли какой-либо элемент новые данные или даже проверить, есть ли новые несохраненные данные во всей форме.

Вы можете настроить следующие часы: $scope.$watch('myForm.modified', handler)и ваш обработчик будет вызываться, если некоторые элементы формы действительно содержат новые данные или если он вернулся в исходное состояние.

Кроме того, вы можете использовать modifiedсвойство отдельных элементов формы, чтобы фактически уменьшить объем данных, отправляемых на сервер через вызов AJAX. Нет необходимости отправлять неизмененные данные.

В качестве бонуса вы можете вернуть форму в исходное состояние с помощью вызова reset()метода формы .

Вы можете найти демонстрацию модуля здесь: http://plnkr.co/edit/g2MDXv81OOBuGo6ORvdt?p=preview

Ура!

Слава Фомин II
источник
Есть ли способ проверить это в контроллере. например, если щелкнуть кнопку x, могу ли я сделать как if (myform.modified) показать всплывающее окно подтверждения?
Flash
Конечно, просто передайте FormController функции вашего контроллера: <form name="myForm">, <button ng-click="vm.doSomething(myForm)">.
Слава Фомин II
спасибо, это что-то сделает, только если форма была изменена правильно?
Flash
Это перейдет FormControllerк doSomething()функции вашего контроллера. Вы можете делать с ним все, что хотите, внутри этой функции, например, проверять, действительно ли форма изменена, проверяя FormController.modifiedлогическое свойство.
Слава Фомин II
Спасибо! Хорошая
Flash