markstewie
markstewie

Reputation: 9587

Angular.js validation. Programatically set form fields properties

I'm trying to set up a form validation systems with angular as follows.

An error class is assigned when the field is both $invalid && $dirty.

This works great for individual fields. Here is an example field.

<div class="control-group" ng-class="getErrorClasses(schoolSignup.first_name)">
      <label class="control-label" for="first_name">First Name</label>
       <div class="controls">
            <input type="text" class="input-xlarge" id="first_name" name="first_name" required ng-maxlength="30" ng-model="school.first_name">
            <span class="help-inline" ng-show="showError(schoolSignup.first_name, 'required')">This field is required</span>
            <span class="help-inline" ng-show="showError(schoolSignup.first_name, 'maxlength')">Maximum of 30 character allowed</span>
        </div>
   </div>

schoolSignup is the name of the form.

ng-class="getErrorClasses(schoolSignup.first_name)"> is defined in the controller as

$scope.getErrorClasses = function(ngModelContoller) {
        return {
            error: ngModelContoller.$invalid && ngModelContoller.$dirty
        };
    };

And on the error help items ng-show="showError(schoolSignup.first_name, 'required')" is defined as:

$scope.showError = function(ngModelController, error) {
      return ngModelController.$dirty && ngModelController.$error[error];
  };

This all works fine.

However, what I want to do is make it so if the user clicks the submit button and all the individual fields that are required are invalid then show the required error message next to the appropriate fields.

This will require setting all the individual fields to $dirty and the $error['required'] value to true based on this system.

I have set up a directive on the submit button called can-save as follows which has access to the form.

<button class="btn btn-primary btn-large" type="submit" can-save="schoolSignup">Register</button>

-

.directive('canSave', function () {
    return function (scope, element, attrs) {

        var form = scope.$eval(attrs.canSave);

        var valid = false;

        element.click(function(){
            if(!valid)
            {
                // show errors

                return false;
            }

            return true;
        });

        scope.$watch(function() {
            return form.$dirty && form.$valid;
        }, function(value) {
            valid = !!value;
        });
    }

});

This all works except for making the errors show as desired.

Any ideas on how to achieve this would be appreciated.

Upvotes: 0

Views: 5372

Answers (1)

markstewie
markstewie

Reputation: 9587

For anyone interested, I've amended my directive to loop through the errors and set each to $dirty and then run $rootScope.$digest():

.directive('canSave', function ($rootScope) {
    return function (scope, element, attrs) {

        var form = scope.$eval(attrs.canSave);

        element.click(function () {
            if(form.$dirty && form.$valid) {
                return true;
            } else {
                // show errors
                angular.forEach(form.$error, function (value, key) {
                    var type = form.$error[key];

                    angular.forEach(type, function (item) {
                        item.$dirty = true;
                        item.$pristine = false;
                    });
                });

                $rootScope.$digest();

                return false;
            }
        });
    }
});

Upvotes: 2

Related Questions