AngularJS: list all form errors

AngularjsAngularjs Ng-Repeat

Angularjs Problem Overview


Background: I am currently working on an application with tabs; and I'd like to list the fields / sections that fail validation, to direct the user to look for errors in the right tab.

So I tried to leverage form.$error to do so; yet I don't fully get it working.

If validation errors occur inside a ng-repeat, e.g.:

<div ng-repeat="url in urls" ng-form="form">
  <input name="inumber" required ng-model="url" />
  <br />
</div>

Empty values result in form.$error containing the following:

{ "required": [
{
"inumber": {}
},
{
"inumber": {}
}
] }

On the other hand, if validation errors occur outside this ng-repeat:

<input ng-model="name" name="iname" required="true" />

The form.$error object contains the following:

{ "required": [ {} ] }
yet, I'd expect the following:

{ "required": [ {'iname': {} } ] }

Any ideas on why the name of the element is missing?

A running plunkr can be found here: http://plnkr.co/x6wQMp

Angularjs Solutions


Solution 1 - Angularjs

As @c0bra pointed out in the comments the form.$error object is populated, it just doesn't like being dumped out as JSON.

Looping through form.$errors and it's nested objects will get the desired result however.

<ul>
  <li ng-repeat="(key, errors) in form.$error track by $index"> <strong>{{ key }}</strong> errors
    <ul>
      <li ng-repeat="e in errors">{{ e.$name }} has an error: <strong>{{ key }}</strong>.</li>
    </ul>
  </li>
</ul>

All the credit goes to c0bra on this.

Another option is to use one of the solutions from this question to assign unique names to the dynamically created inputs.

Solution 2 - Angularjs

I made a function that you pass the form to. If there are form errors it will display them in the console. It shows the objects so you can take a look. I put this in my save function.

function formErrors(form){
  var errors = [];
  for(var key in form.$error){
    errors.push(key + "=" + form.$error);
  }
  if(errors.length > 0){
    console.log("Form Has Errors");
    console.log(form.$error);
  }
};

Solution 3 - Angularjs

Brett DeWoody's answer is correct. I wanted to do the logic in my controller though. So I wrote the below, which is based off of the answer user5045936 gave. This may also help some of you who want to go the controller route. By the way Im using the toaster directive to show my users validation messages.

 if (!vm.myForm.$valid) {
            var errors = [];

            for (var key in vm.myForm.$error) {
                for (var index = 0; index < vm.myForm.$error[key].length; index++) {
                    errors.push(vm.myForm.$error[key][index].$name + ' is required.');
                }
            }

            toaster.pop('warning', 'Information Missing', 'The ' + errors[0]);

            return;
        }

Solution 4 - Angularjs

If you have nested forms then you will find this helpful:

 function touchErrorFields(form) {
    angular.forEach(form.$error, function (field) {
      angular.forEach(field, function(errorField) {
        if (!errorField.hasOwnProperty('$setTouched')) {
          touchErrorFields(errorField);
        } else {
          errorField.$setTouched();
        }
      })
    });
  }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionmichaelView Question on Stackoverflow
Solution 1 - AngularjsBrett DeWoodyView Answer on Stackoverflow
Solution 2 - Angularjsuser5045936View Answer on Stackoverflow
Solution 3 - AngularjstxavierView Answer on Stackoverflow
Solution 4 - Angularjsvlio20View Answer on Stackoverflow