I use a directive to check if the email is already registered in my DB.
app.directive('uniqueEmail', function($http) {
var toId;
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, elem, attr, ctrl) {
//when the scope changes, check the email.
scope.$watch(attr.ngModel, function(value) {
// if there was a previous attempt, stop it.
if(toId) clearTimeout(toId);
// start a new attempt with a delay to keep it from
// getting too "chatty".
toId = setTimeout(function(){
// call to some API that returns { isValid: true } or { isValid: false }
$http.get('check/e/' + value).success(function(data) {
//set the validity of the field
ctrl.$setValidity("uniqueEmail", data.isValid);
});
}, 200);
})
}
}
});
and my input :
<form name="myForm">
<input type="email" ng-model="userEmail" name="userEmail" required unique-email/>
<tt>myForm.userEmail.$error = {{myForm.userEmail.$error}}</tt>
</form>
My problem is that the $error.uniqueEmail is always false. the $http response shows false when email is available and true when email is already registered. (adding alert(data.isValid) confirms that.
I also tryed to switch the true/false statement from the $http reponse without sucess (email already registered = false and email available = true).
What am i missing ?
Edit : Ok i found the problem
ctrl.$setValidity("uniqueemail", false) shows true
and ctrl.$setValidity("uniqueemail", true) shows false
No need for a regexp at all if you use a type="email"
. Angular will care about the validation for you.
angular.module('directives.emailUnique', [])
.directive('emailUnique', ['$http', function ($http) {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, el, attrs, ctrl) {
ctrl.$parsers.push(function (viewValue) {
if (!viewValue) {
ctrl.$setValidity('emailUnique', true);
return undefined;
}
$http.get('/api/emailunique/' + viewValue).success(function (data) {
if (data.data && data.data.unique)
ctrl.$setValidity('emailUnique', true);
else
ctrl.$setValidity('emailUnique', false);
}).error(function () {
alert('Sorry, a technical issue prevents to validate your email.\n ' +
'Thanks to retry later.');
});
return viewValue;
});
}
};
}]);
Achieving purely practicing TDD to handle every cases, here's the spec:
describe('emailUnique directive', function () {
var $scope, form, $httpBackend;
beforeEach(function () {
module('directives.emailUnique');
inject(function ($compile, $rootScope, _$httpBackend_) {
$scope = $rootScope;
$httpBackend = _$httpBackend_;
var element = angular.element(
'<form name="form" novalidate><input name="email" type="email" ng-model="model.email" required email-unique/></form>'
);
$scope.model = {
email: ''
};
$compile(element)($scope);
$scope.$digest();
form = $scope.form;
});
});
afterEach(function () {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
describe('email uniqueness', function () {
it('should return the current value if the email is a valid one', function () {
$httpBackend.whenGET('/api/emailunique/[email protected]').respond(200, {data: {unique: true}});
setViewValue('[email protected]');
$httpBackend.flush();
expect($scope.model.email).toBe('[email protected]');
$httpBackend.whenGET('/api/emailunique/[email protected]').respond(200, {data: {unique: true}});
setViewValue('[email protected]');
$httpBackend.flush();
expect($scope.model.email).toBe('[email protected]');
});
it('emailUnique validity should not be evaluated to true if email is invalid', function () {
setViewValue('michael');
expect(form.email.$error.emailUnique).not.toBe(true);
});
it('should set emailUnique validity to true if email is unique', function () {
$httpBackend.whenGET('/api/emailunique/[email protected]').respond(200, {data: {unique: true}});
setViewValue('[email protected]');
$httpBackend.flush();
expect(form.email.$error.emailUnique).toBe(false);
});
it('should not set emailUnique validity to true if email is not unique', function(){
$httpBackend.whenGET('/api/emailunique/[email protected]').respond(200, {data: {unique: false}});
setViewValue('[email protected]');
$httpBackend.flush();
expect(form.email.$error.emailUnique).toBe(true);
});
it('should call emailUnique server api if email is valid, to check for uniqueness', function(){
$httpBackend.expectGET('/api/emailunique/[email protected]').respond(200, {data: {unique: true}});
setViewValue('[email protected]');
$httpBackend.flush();
});
it('should set emailUnique to true if ' +
'it was first evaluated as not unique and then back to an invalid one', function(){
$httpBackend.whenGET('/api/emailunique/[email protected]').respond(200, {data: {unique: false}});
setViewValue('[email protected]');
$httpBackend.flush();
setViewValue('michaelgmail.com');
expect(form.email.$error.emailUnique).toBe(false);
});
});
function setViewValue(email) {
form.email.$setViewValue(email);
$scope.$digest();
}
});
You could use some directive like this also
app.directive('uniqueEmail', ["$http",
function($http) {
return {
require: 'ngModel',
restrict: 'A',
link: function(scope, elem, attrs, ctrl) {
/*We need to check that the value is different to the original*/
/*using push() here to run it as the last parser, after we are sure that other validators were run*/
ctrl.$parsers.push(function(viewValue) {
var filter = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
if (filter.test(viewValue)) {
$http.get('check/e/' + viewValue).success(function(data) {
//set the validity of the field
ctrl.$setValidity("uniqueEmail", data.isValid);
});
return viewValue;
}
});
}
};
}
]);
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