Watch form model for changes
Asked Answered
N

2

11

Assuming a given form such as <form name="myForm">, it's easy enough to watch for validity, error, dirty state, etc. using a simple watch:

$scope.$watch('myForm.$valid', function() {
  console.log('form is valid? ', $scope.myForm.$valid); 
});

However, there doesn't appear to be an easy way to watch if any given input in this form has changed. Deep watching like so, does not work:

$scope.$watch('myForm', function() {
  console.log('an input has changed'); //this will never fire
}, true);

$watchCollection only goes one level deep, which means I would have to create a new watch for every input. Not ideal.

What is an elegant way to watch a form for changes on any input without having to resort to multiple watches, or placing ng-change on each input?

Nerval answered 6/5, 2015 at 15:19 Comment(2)
possible duplicate of AngularJS 1.3 - `ng-change`-like functionality for the entire formMalvoisie
The directive solution in that question works, but it's not what I had in mind (i.e. not elegant, since it requires blur in order to work). Ideally I would like this to work in a similar way that angular internally sets a form to $valid or $error immediately after a child input changes appropriately.Nerval
W
7

Concerning the possible duplicate and your comment:

The directive solution in that question works, but it's not what I had in mind (i.e. not elegant, since it requires blur in order to work).

It works if you add true as third parameter for your $watch:

$scope.$watch('myFormdata', function() {
    console.log('form model has been changed');
}, true);

Further information see the docs.

Working Fiddle (check console log)


Another more angular way would be to use angular's $pristine. This boolean property will be set to false once you manipulate the form model:

Fiddle

Woodcutter answered 6/5, 2015 at 16:15 Comment(3)
Indeed I'm aware that it works that way assuming your form fields all share a common parent object. And I can use a watch in that way - I was ideally hoping there would be a way to watch using the form name, rather than the model each input is bound toNerval
It depends if you need the new value. If you just want to now that something has changed you sould be using $pristine.Woodcutter
It's in the context of an autosave, so while $pristine or $dirty would be useful for the first change, they are not useful for every subsequent change unless I were to manually set the pristine/dirty value on every save which seems a bit hacky to me. I'll probably have to settle for a deep watch on the model the inputs share.Nerval
C
4

Based on my experience with my forms (new dev, but working with Angular for a while now), the elegant way to watch a form for changes is actually not to use any type of watch statement at all actually.
Use the built-in Angular boolean $pristine or $dirty and those values will change automatically on any input field or checkbox.
The catch is: it will not change the value if you add or splice from an array which had me stumped for a while.
The best fix for me was to manually do $scope.MyForm.$setDirty(); whenever I was adding or removing from my different arrays. Worked like a charm!

Coefficient answered 29/7, 2015 at 18:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.