Skip to content

Instantly share code, notes, and snippets.

@wvuong
Created July 3, 2013 03:19
Show Gist options
  • Save wvuong/5915184 to your computer and use it in GitHub Desktop.
Save wvuong/5915184 to your computer and use it in GitHub Desktop.
Example of custom validation for an account registration form via directives. Note: the validateUnique directive's expression expects a promise because the server-side uniqueness check is asynchronous.
angular.module('registerapp.controllers', ['registerapp.services']).
controller('RegisterFormController', ['$scope', '$window', '$location', 'UsernameService', '$q', function($scope, $window, $location, UsernameService, $q) {
$scope.user = {};
$scope.checkUsername = function() {
if ($scope.user.username) {
return UsernameService.checkForDuplicateUsername($scope.user.username);
}
};
$scope.submitForm = function() {
$http.post(contextPath + '/register', $scope.user)
.success(function(data, status) {
$location.path('/done');
})
.error(function(data, status) {
$window.alert('account registration unsuccessful, error code ' + status);
});
};
}]);
angular.module('common.directives', []).
directive('validateUnique', function() {
return {
restrict: 'A', // only activate on element attribute
require: 'ngModel', // get a hold of NgModelController,
link: function(scope, element, attrs, ngModel) {
if(!ngModel) return; // do nothing if no ng-model
// attach listener to watch model value for change and revalidate every change
element.on('keyup', function() {
scope.$apply(function() {
// eval the expression in the validate-unique attribute
var promise = scope.$eval(attrs.validateUnique);
if (promise) {
promise.then(function(result) {
if (result === true) {
ngModel.$setValidity('unique', false);
}
else {
ngModel.$setValidity('unique', true);
}
});
}
});
});
}
};
}).
directive('validateSameValueAs', function() {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
// get reference input element
var reference = angular.element('#' + attrs.validateSameValueAs);
if (!reference) {
return;
}
// update validity on key input
element.on('keyup', function() {
scope.$apply(function() {
if (reference.val() === element.val()) {
ngModel.$setValidity('samevalue', true);
}
else {
ngModel.$setValidity('samevalue', false);
}
});
});
// update validity if reference input changes
reference.on('keyup', function() {
scope.$apply(function() {
if (reference.val() === element.val()) {
ngModel.$setValidity('samevalue', true);
}
else {
ngModel.$setValidity('samevalue', false);
}
});
});
}
};
});
<div ng-controller="RegisterFormController">
<form name="registerForm" class="form-register" novalidate ng-submit="submitForm()">
<h2 class="form-signin-heading">Register New Account</h2>
<div class="control-group" ng-class="{error: registerForm.username.$invalid}">
<label class="control-label" for="username">Name</label>
<div class="controls">
<input type="text" id="username" name="username" placeholder="Username" ng-model="user.username"
validate-unique="checkUsername(user.username)"
ng-minlength="4"
ng-maxlength="12"
ng-pattern=/^\w*$/ required>
<span class="help-inline" ng-show="registerForm.username.$valid"><i class="icon-ok"></i> Username OK!</span>
<span class="help-block" ng-show="registerForm.username.$error.required && registerForm.username.$dirty"><i class="icon-warning-sign"></i> Required</span>
<span class="help-block" ng-show="registerForm.username.$error.pattern"><i class="icon-warning-sign"></i> Must be only alphanumeric characters, no spaces</span>
<span class="help-block" ng-show="registerForm.username.$error.unique"><i class="icon-warning-sign"></i> Username is already taken</span>
<span class="help-block" ng-show="registerForm.username.$error.minlength"><i class="icon-warning-sign"></i> Username must be at least 4 characters</span>
<span class="help-block" ng-show="registerForm.username.$error.maxlength"><i class="icon-warning-sign"></i> Username must be at most 12 characters</span>
</div>
</div>
<div class="control-group" ng-class="{error: registerForm.email.$invalid}">
<label class="control-label" for="email">Email Address</label>
<div class="controls">
<input type="email" id="email" name="email" placeholder="Email address" ng-model="user.email" required>
<span class="help-inline" ng-show="registerForm.email.$valid"><i class="icon-ok"></i> Email OK!</span>
<span class="help-block" class="error" ng-show="registerForm.email.$dirty && registerForm.email.$error.required"><i class="icon-warning-sign"></i> Required</span>
<span class="help-block" class="error" ng-show="registerForm.email.$dirty && registerForm.email.$invalid"><i class="icon-warning-sign"></i> Invalid email address</span>
</div>
</div>
<div class="control-group" ng-class="{error: registerForm.password.$invalid || registerForm.password2.$invalid}">
<label class="control-label" for="password">Password</label>
<div class="controls">
<input type="password" id="password" name="password" placeholder="Password" ng-model="user.password" required>
<span class="help-inline" ng-show="registerForm.password.$valid"><i class="icon-ok"></i> Password OK!</span>
<span class="help-block" class="error" ng-show="registerForm.password.$dirty && registerForm.password.$error.required"><i class="icon-warning-sign"></i> Required</span>
</div>
<label class="control-label" for="password2">Reenter Password</label>
<div class="controls">
<input type="password" id="password2" name="password2" placeholder="Password"
ng-model="secondPassword"
validate-same-value-as="password"
required>
<span class="help-inline" ng-show="registerForm.password2.$valid"><i class="icon-ok"></i> Passwords match OK!</span>
<span class="help-block" class="error" ng-show="registerForm.password2.$dirty && registerForm.password2.$error.required"><i class="icon-warning-sign"></i> Required</span>
<span class="help-block" class="error" ng-show="registerForm.password2.$dirty && registerForm.password2.$error.samevalue"><i class="icon-warning-sign"></i> Passwords do not match.</span>
</div>
</div>
<div class="form-actions">
<button class="btn btn-large btn-primary" type="submit" ng-disabled="registerForm.$invalid">Register Account</button>
</div>
</form>
</div>
angular.module('registerapp.services', ['common.filters']).
factory('UsernameService', ['$filter', '$http', '$log', '$q', function($filter, $http, $log, $q) {
var fn = $filter('relativeUrl');
return {
checkForDuplicateUsername : function(value) {
var deferred = $q.defer();
$http({
url: fn('/register/check'),
method: 'GET',
params: {username: value}
})
.success(function(data) { // json data returned by server has an exists property
deferred.resolve(data.exists === true);
})
.error(function() {
deferred.reject();
});
return deferred.promise;
}
};
}]);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment