So this is how you can use ajax validation with an AngularJS directive to check if a username is already in use (by another registered user).
- User types a username
- Ajax request to back-end with username
- back-end checks if username already exists
- front end displays outcome
What is going on:
- There is an ng directive to check for unique values
- There is an ng service to perform the ajax checks to the back-end
- There is a back-end api function which checks the db
That’s pretty much it.
ng-unique-directive.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
/** * @ngdirective * Sets the current navbar option in focus. */ angular.module("app").directive("ngUnique", function(AuthService) { return { restrict: 'A', require: 'ngModel', link: function (scope, element, attrs, ngModel) { element.bind('blur', function (e) { if (!ngModel || !element.val()) return; var keyProperty = scope.$eval(attrs.ngUnique); var currentValue = element.val(); AuthService.checkUniqueValue(keyProperty.key, keyProperty.property, currentValue) .then(function (unique) { //Ensure value that being checked hasn't changed //since the Ajax call was made if (currentValue == element.val()) { console.log('unique = '+unique); ngModel.$setValidity('unique', unique); scope.$broadcast('show-errors-check-validity'); } }); }); } } }); |
auth-service.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
... //checks if a field is unique (ie email or username on signup). checkUniqueValue: function(id, property, value) { var data = { id: id, property: property, value: value }; return $http.post("/api/auth/signup/isuniquevalue", data).then( function(res) { return res.data.isUnique; }); } ... |
ng template (view)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
<form id="signup_form" name="signup_form" role="form" ng-submit="signup()" novalidate> <div class="form-group" show-errors> <input type="email" name="email" placeholder="Email" class="form-control" ng-model="credentials.email" required autofocus /> <p class="help-block" ng-show="signup_form.email.$error.required">Email is required.</p> <p class="help-block" ng-if="signup_form.email.$error.email">Must be a valid email.</p> </div> <div class="form-group" show-errors> <input type="text" name="username" placeholder="Username" class="form-control" ng-model="credentials.username" ng-minlength=5 required ng-unique="{key: 'users', property: 'username'}" autofocus /> <span class="glyphicon glyphicon-ok form-control-icon success"></span> <p class="help-block" ng-show="signup_form.username.$error.required">Username is required.</p> <p class="help-block" ng-if="signup_form.username.$error.minlength">Must be at least 5 characters.</p> <p class="help-block" ng-show="signup_form.username.$error.unique">Username is already taken.</p> </div> <div class="form-group" show-errors> <input type="password" name="password" placeholder="Password" class="form-control" ng-model="credentials.password" required /> <p class="help-block" ng-show="signup_form.password.$error.required">Password is required.</p> </div> <div class="form-group"> <button type="submit" class="btn btn-primary btn-lg"><i class="fa fa-lock"></i> Signup</button> </div> </form> |
Example back-end (Laravel PHP)
routes:
1 2 3 |
controller:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
//checks if a value is unique for a field in the users table. //TODO: add csrf token to these requests. public function isUniqueValue() { $id = Input::json('id'); $property = Input::json('property'); $value = Input::json('value'); $user = DB::table($id)->where($property, $value)->get(); $result = (count($user) == 0); return Response::json(array( 'error' => false, 'isUnique' => $result ), 200 ); } |
As you can see from the console result the check is working like we want.
Further reading:
https://codepen.io/sevilayha/pen/xFcdI
https://weblogs.asp.net/dwahlin/building-a-custom-angularjs-unique-value-directive
It does not work