I have have my angular app validating a sign-up form. On submit, the server also validates the data. I'm outputting error messages in angular using ng-messages.
Here is a shortened version of my form, which works perfectly so far.
<form name="signUpForm" novalidate data-ng-submit="attemptSignUp()"> <label for="firstName">First name</label> <input type="email" name="email" id="email" required data-ng-model="data.user.email" /> <div class="error" data-ng-messages="signUpForm.email.$error" data-ng-show="signUpForm.$submitted" data-ng-cloak> <p data-ng-message="required">Please provide your email</p> </div> </form>
The server verifies the email address is unique, and if not, returns a 422 error (from Laravel 5), with an array of errors.
[ 'email' => 'This email is already in use' ]
I'd like to merge in this, and any other messages sent back from the server into their relevant ng-messages
block. Any idea how I could accomplish it?
in controller: $scope. errors = []; $scope. hasError = false; $scope.
Overview. ngMessages is a directive that is designed to show and hide messages based on the state of a key/value object that it listens on. The directive itself complements error message reporting with the ngModel $error object (which stores a key/value state of validation errors).
$dirty means the user has changed the input value, $invalid means the address itself is invalid. Therefore the error is only shown if the user has actively changed the input value to either an empty or invalid value.
A simple solution is to have two arrays. One for client side and one for server side errors which is populated in your controller. You can hide the server side errors if client errors exists or opposit to avoid double messages.
The reason I choose to have two arrays instead of populating the forms array is that the JavaScript controller should not know or be dependent on the structure of the HTML. The HTML AngularJS template should be bound to the controller, not opposit.
<form name="signUpForm" novalidate data-ng-submit="attemptSignUp()"> <label for="email">E-mail <input type="email" name="email" id="email" required data-ng-model="data.user.email" /> <div class="error" data-ng-messages="signUpForm.email.$error" data-ng-show="signUpForm.$submitted" data-ng-cloak> <p data-ng-message="required">Please provide your email</p> </div> <div class="error" data-ng-messages="serverErrors" data-ng-show="signUpForm.$submitted" data-ng-cloak> <p data-ng-message="emailexists">Email already exists</p> </div> </label </form>
A note on the label: Users using screen-readers will not get your error messages read out loud to them if they are not wrapped inside the label.
Well, this is not the most elegant solution since you really should leverage the asyncValidators in angular 1.3.x and then create your custom validation directives.
Resources
http://plnkr.co/edit/s4jJAOqehBkFUC9osMsy?p=preview found in the post by this guy.
Possibly here http://odetocode.com/blogs/scott/archive/2014/10/16/working-with-validators-and-messages-in-angularjs.aspx
And of course in the docs
But be cautious as this is not in any way a complete example ready to be used. It's mostly here for demo purpose and to sort of give you an idea where to start. I have not bothered with clearing any previous errors, revalidating the form or taken into account other validation errors.
Imagine your controller looks like this
$scope.serverValidations = {}; $scope.attemptSignUp = function(){ Api.validateEmail($scope.email).then(angular.noop, function(data){ $scope.serverValidations = data for(prop in $scope.serverValidations){ if($scope.signUpForm[prop]){ angular.forEach($scope.serverValidations[prop],function(validation){ $scope.signUpForm[prop].$setValidity(validation.type, false); }); } } }); }
and your response data containing validation errors look like this
{ email:[ {type:'unique', message:'This email is already in use'} ], name:[ {type:'maxlength', message:'Your name is to long, get a new one :)'} ] };
Then in your HTML you could do like this
<div class="error" data-ng-messages="signUpForm.name.$error" data-ng-cloak=""> <p data-ng-message="required">You don't have a name?</p> <p ng-repeat="validation in serverValidations['name']" ng-message="{{validation.type}}">{{validation.message}}</p> </div>
Here's a dirty Codepen for you: http://codepen.io/anon/pen/yyzMgG?editors=101 When you press submit, after 2 seconds (the time it takes to hit the fake server) your server validations are presented.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With