Model Options and Pristine Forms In AngularJS

Tuesday, June 10, 2014

Here is a plunk that demonstrates how to reset an Angular form. The form itself will display any element with a dirty flag using a thick red border. The ngModel and ngForm directives automatically add the ng-dirty class to elements with a dirty flag, and the CSS rule applied is like so:

.ng-dirty {
    border: red 5px solid;
}

Notice how typing into an input not only makes the input dirty, but also makes the form itself dirty (a double border).

Dirty AngularJS Form

You might also notice when typing into the first input how the dirty flag takes a couple seconds to appear. The delay is because of the new ngModelOptions directive in 1.3. With ngModelOptions you can specify the events required to push values into the model (perhaps using the blur event instead of the keypress event), and also debounce the data binding by specifying a number of quiet milliseconds to elapse before pushing data. The example plunk is waiting for 2,000 milliseconds.

<form name="editUserForm">

    <input type="text" ng-model="user.firstName" ng-model-options="{debounce:1000}"/>
    <input type="text" ng-model="user.lastName"/>
    <input type="submit" value="Submit"/>
    <input type="button" value="Reset" ng-click="reset()"/>

</form>

The reset button will set the form back into a pristine state using $setPristine. $setPristine recursively sets all the controls inside the form to a pristine state, too. It’s up to the application logic to replace the data, perhaps by making a copy of the original form data, as shown below.

$scope.user = {
    firstName: "Scott",
    lastName: "Allen"
};

$scope.originalUser = angular.copy($scope.user);

$scope.reset = function(){
    $scope.user = angular.copy($scope.originalUser);
    $scope.editUserForm.$setPristine();
};

Quite a bit of power from a minimum amount of code.


Comments
gravatar Calvin Tuesday, June 10, 2014
This is a great feature! I have tried to use it to detect if there are any changes in a form, but unfortunately it doesn't work correctly when a field is reverted to the original value. Any suggestions on how to do this?
gravatar scott Wednesday, June 11, 2014
@Calvin: I'm not quite sure what you are saying - are you trying to make a single form input pristine?
gravatar Calvin Wednesday, June 11, 2014
My requirement is that I have a form and I want to detect if the user has made any changes to any of the fields in the form. If the user tries to leave the page and if there are any changes in the form I want to display a dialog. I was planning to use isdirty property on the scope, but unfortunately if the user modifies a field and then reverts his changes, isdirty property is still true.
gravatar Scott Wednesday, June 11, 2014
@Calvin: This is exactly what setPristine can do - clear the dirty flag. What version of the framework are you using?
gravatar zeljko Friday, June 13, 2014
@scott. I think what Calvin tries to say is: You have the name field set to Scott by default, and then you decide to change it and type e.g. Tom. Then you decide, you didn't want to change the name and type in Scott again. The name field and the form are marked as $dirty, although you have reentered the original values. Sure, you could mark the field manually $pristine, but then you had to implement some change tracking. It would be nice if angularjs could mark the field $pristine if you revert the field to it's default value.
Your Comment
by K. Scott Allen K.Scott Allen
My Pluralsight Courses
The Podcast!