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?

JasonMArcher
  • 14,195
  • 22
  • 56
  • 52
Duncan
  • 2,550
  • 2
  • 17
  • 18
  • 3
    possible duplicate of [AngularJS 1.3 - \`ng-change\`-like functionality for the entire form](http://stackoverflow.com/questions/28677638/angularjs-1-3-ng-change-like-functionality-for-the-entire-form) – dting May 06 '15 at 15:34
  • 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. – Duncan May 06 '15 at 15:47

2 Answers2

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

Community
  • 1
  • 1
DonJuwe
  • 4,477
  • 3
  • 34
  • 59
  • 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 to – Duncan May 06 '15 at 17:12
  • It depends if you need the new value. If you just want to now that something has changed you sould be using `$pristine`. – DonJuwe May 07 '15 at 07:09
  • 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. – Duncan May 07 '15 at 13:47
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!

serenesat
  • 4,611
  • 10
  • 37
  • 53
leviathon
  • 51
  • 3