Angular Sign Up Form
Angular Sign Up Form
by Andrew Pougher
HTML
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.1/angular.js"></script>
<div class="container" ng-app="myApp">
<div class="col-lg-offset-4 col-lg-4">
<div class="panel">
<div class="panel-heading">Sign up</div>
<form name="form" method="post" action="/signup" novalidate>
<div class="form-group">
<label for="username" class="control-label">Username</label>
<input type="text" name="username" id="username" placeholder="Username" unique-username required ng-model="username" autofocus class="form-control"><i ng-show="busy" class="halflings-icon refresh rotating"></i><span ng-show="form.username.$dirty && form.username.$error.required" class="help-block">Please choose a username</span><span ng-show="form.username.$dirty && form.username.$error.isTaken" class="help-block">Username already taken</span><span ng-show="form.username.$dirty && form.username.$error.invalidChars" class="help-block">Username may not contain any non-url-safe characters</span>
</div>
<div class="form-group">
<label for="email" class="control-label">Email</label>
<input type="email" ng-model="email" name="email" id="email" placeholder="Email" required class="form-control"><span ng-show="form.email.$dirty && form.email.$error.email" class="help-block">Email is invalid</span>
</div>
<div class="form-group">
<label for="password" class="control-label">Password</label>
<input type="password" name="password" id="password" ng-model="password" required match="verification" class="form-control"><span ng-show="form.password.$dirty && form.password.$error.required" class="help-block">Please enter a...
CSS
input.ng-invalid.ng-dirty {
border-color: #b94a48;
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,0.075);
box-shadow: inset 0 1px 1px rgba(0,0,0,0.075);
}
input.ng-invalid.ng-dirty ~ .help-block {
color: #b94a48;
}
input.ng-valid.ng-dirty {
border-color: #468847;
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,0.075);
box-shadow: inset 0 1px 1px rgba(0,0,0,0.075);
}
@-webkit-keyframes rotating {
from {
-webkit-transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
}
}
.rotating {
float: right;
position: relative;
top: -24px;
right: 10px;
-webkit-animation: rotating 1s linear infinite;
}
JavaScript
var app = angular.module('myApp', []);
//
app.directive('uniqueUsername', ['$http', function($http) {
return {
require: 'ngModel',
link: function(scope, elem, attrs, ctrl) {
scope.busy = false;
scope.$watch(attrs.ngModel, function(value) {
// hide old error messages
ctrl.$setValidity('isTaken', true);
ctrl.$setValidity('invalidChars', true);
if (!value) {
// don't send undefined to the server during dirty check
// empty username is caught by required directive
return;
}
scope.busy = true;
$http.post('/signup/check/username', {username: value})
.success(function(data) {
// everything is fine -> do nothing
scope.busy = false;
})
.error(function(data) {
// display new error message
if (data.isTaken) {
ctrl.$setValidity('isTaken', false);
} else if (data.invalidChars) {
ctrl.$setValidity('invalidChars', false);
}
scope.busy = false;
});
})
}
}
}]);
// http://codepen.io/brunoscopelliti/pen/ECyka
app.directive('match', [function () {
return {
require: 'ngModel',
link: function (scope, elem, attrs, ctrl) {
scope.$watch('[' + attrs.ngModel + ', ' + attrs.match + ']', function(value){
ctrl.$setValidity('match', value[0] === value[1] );
}, true);
}
}
}]);