I would like to do an equivalent of ng-change
for the entire form whenever there is a change in one of its input fields.
I know that since AngularJS 1.3 I have the debounce option but it applies only for a single input.
I'm looking for a "debounce"/"on change" functionality that will apply for the entire form.
There isn't a built-in way to do ng-change
for a form.
It may not even be needed, because if you organized your view model properly, then your form inputs are likely bound to a certain scope-exposed property:
$scope.formData = {};
and in the View:
<form name="form1">
<input ng-model="formData.a">
<input ng-model="formData.b">
</form>
Then you could deep-watch (with $watch
) for model changes (and apply whatever debounce option on elements that you need):
$scope.$watch("formData", function(){
console.log("something has changed");
}, true);
Then problem is, of course, that this is a deep-watch and it is expensive. Also, it reacts not only to changes in the Form, but also to a change in formData
from any source.
So, as an alternative, you could create your own directive to compliment the form and react to form's change events.
.directive("formOnChange", function($parse){
return {
require: "form",
link: function(scope, element, attrs){
var cb = $parse(attrs.formOnChange);
element.on("change", function(){
cb(scope);
});
}
}
});
and the usage is:
<form name="form1" form-on-change="doSomething()">
<input ng-model="formData.a">
<input ng-model="formData.b">
</form>
plunker for illustration.
Note, that the "change" event is fired only on blur for a text input, as per jQuery documentation:
The change
event is sent to an element when its value changes. This event is limited to <input>
elements, <textarea>
boxes and <select>
elements. For select boxes, checkboxes, and radio buttons, the event is fired immediately when the user makes a selection with the mouse, but for the other element types the event is deferred until the element loses focus.
one "hacky" way to do this is by setting a watcher to the form dirty, valid depending on your requirements you can do something like
$scope.$watch('form.$dirty',function(v){
if(!v){return}
form.$setPristine()
/*do something here*/
})
this will execute everytime the form gets modified, if you only want to execute your code on valid modified form you can do
if(!v || form.$invalid){return}
and if you only want to execute your code when the form steps to $valid state just need to set up your watcher for 'form.$valid'
if you don't like to pollute your scope with watchers, you can always create a directive around the form that exposes a on-change api event and internally takes care of the watcher
As per Eric Soyke comment you could hook up the check of the form change on the keyup event.
This way you could simply use the builtin directive ng-keyup:
<form name="form1" ng-keyup="doSomething()">
okay, super super late answer ... but this works pretty neat
// html
<form name="$ctrl.form">...</form>
// controller
function $postLink() {
ctrl.form.$$element.on('change', function () {
console.log('fired');
});
}