AngularJS: 自动检测模型变化

假设我想在模型的值发生变化时自动运行一些代码(比如将数据保存到服务器)。唯一的方法是通过在每个控件上设置类似 ng-change的东西来改变模型吗?

也就是说,对于视图,当模型被更改时,事情就会发生变化,而不必显式地连接任何东西。能够运行保存到服务器的代码有没有类似的方法?差不多

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

就像你看到的那样。

151118 次浏览

In views with \{\{}} and/or ng-model, Angular is setting up $watch()es for you behind the scenes.

By default $watch compares by reference. If you set the third parameter to $watch to true, Angular will instead "shallow" watch the object for changes. For arrays this means comparing the array items, for object maps this means watching the properties. So this should do what you want:

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

Update: Angular v1.2 added a new method for this, `$watchCollection():

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

Note that the word "shallow" is used to describe the comparison rather than "deep" because references are not followed -- e.g., if the watched object contains a property value that is a reference to another object, that reference is not followed to compare the other object.

And if you need to style your form elements according to it's state (modified/not modified) dynamically or to test whether some values has actually changed, you can use the following module, developed by myself: https://github.com/betsol/angular-input-modified

It adds additional properties and methods to the form and it's child elements. With it, you can test whether some element contains new data or even test if entire form has new unsaved data.

You can setup the following watch: $scope.$watch('myForm.modified', handler) and your handler will be called if some form elements actually contains new data or if it reversed to initial state.

Also, you can use modified property of individual form elements to actually reduce amount of data sent to a server via AJAX call. There is no need to send unchanged data.

As a bonus, you can revert your form to initial state via call to form's reset() method.

You can find the module's demo here: http://plnkr.co/edit/g2MDXv81OOBuGo6ORvdt?p=preview

Cheers!

Detect change in a single model

$scope.$watchCollection('model1', function () {
//...
}, true);

Detect change in a multiple models

$scope.$watchCollection('[model1, model2, model3]', function () {
//...
}, true);