battmanz battmanz - 4 months ago 10
HTML Question

How do I reset a form including removing all validation errors?

I have an Angular form. The fields are validated using the

ng-pattern
attribute. I also have a reset button. I'm using the Ui.Utils Event Binder to handle the
reset
event like so:

<form name="searchForm" id="searchForm" ui-event="{reset: 'reset(searchForm)'}" ng-submit="search()">
<div>
<label>
Area Code
<input type="tel" name="areaCode" ng-model="areaCode" ng-pattern="/^([0-9]{3})?$/">
</label>

<div ng-messages="searchForm.areaCode.$error">
<div class="error" ng-message="pattern">The area code must be three digits</div>
</div>
</div>

<div>
<label>
Phone Number
<input type="tel" name="phoneNumber" ng-model="phoneNumber" ng-pattern="/^([0-9]{7})?$/">
</label>

<div ng-messages="searchForm.phoneNumber.$error">
<div class="error" ng-message="pattern">The phone number must be seven digits</div>
</div>
</div>

<br>
<div>
<button type="reset">Reset</button>
<button type="submit" ng-disabled="searchForm.$invalid">Search</button>
</div>
</form>


As you can see, when the form is reset it calls the
reset
method on the
$scope
. Here's what the entire controller looks like:

angular.module('app').controller('mainController', function($scope) {
$scope.resetCount = 0;

$scope.reset = function(form) {
form.$setPristine();
form.$setUntouched();
$scope.resetCount++;
};

$scope.search = function() {
alert('Searching');
};
});


I'm calling
form.$setPristine()
and
form.$setUntouched
, following the advice from another question here on Stack Overflow. The only reason I added the counter was to prove that the code is being called (which it is).

The problem is that even after reseting the form, the validation messages don't go away. You can see the full code on Plunker. Here's a screenshot showing that the errors don't go away:

Validation Errors

Answer

I started with the comment from @Brett and built upon it. I actually have multiple forms and each form has many fields (more than just the two shown). So I wanted a general solution.

I noticed that the Angular form object has a property for each control (input, select, textarea, etc) as well as some other Angular properties. Each of the Angular properties, though, begins with a dollar sign ($). So I ended up doing this (including the comment for the benefit of other programmers):

$scope.reset = function(form) {
    // Each control (input, select, textarea, etc) gets added as a property of the form.
    // The form has other built-in properties as well. However it's easy to filter those out,
    // because the Angular team has chosen to prefix each one with a dollar sign.
    // So, we just avoid those properties that begin with a dollar sign.
    let controlNames = Object.keys(form).filter(key => key.indexOf('$') !== 0);

    // Set each control back to undefined. This is the only way to clear validation messages.
    // Calling `form.$setPristine()` won't do it (even though you wish it would).
    for (let name of controlNames) {
        let control = form[name];
        control.$setViewValue(undefined);
    }

    form.$setPristine();
    form.$setUntouched();
};

I'm using an ES6 arrow function. That could also be easily replaced by a regular function expression.