Sep 16, 2013

Username Availability Check with AngularJS in ASP.NET MVC

In my previous article, We have implemented to check username availability in ASP.NET Web Forms using jQuery Validation Plugin. In this article, we will do same thing in ASP.NET MVC, but using AngularJS(An open-source MV* JavaScript framework for building dynamic web apps).

I am using ASP.NET MVC > Internet application template in VS2012 for this post.

Install Angularjs Nuget package by running following command in package manager console:

Install-Package angularjs

Server Side Controller:

In AccountController, Add following signup actions:


        [AllowAnonymous]
        public ActionResult SignUp()
        {
            return View();
        }
	
	
	[HttpPost]
        [AllowAnonymous]    
        public JsonResult SignUp(RegisterModel model)
        {
            if (ModelState.IsValid)
            {
                // Attempt to register the user
                try
                {
                    WebSecurity.CreateUserAndAccount(model.UserName, model.Password);
                    WebSecurity.Login(model.UserName, model.Password);
                      return Json(new { success = true});                  
                }
                catch (MembershipCreateUserException e)
                {
                    ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
                }
            }
            return Json(new
            {
                success = false,
                errors = ModelState.Keys.SelectMany(k => ModelState[k].Errors)
                                .Select(m => m.ErrorMessage).ToArray()
            });
        }

In above action, the default RegisterModel(in AccountModels) is used.


 public class RegisterModel
    {
        [Required]
        [Display(Name = "User name")]
        public string UserName { get; set; }

        [Required]
        [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
        [DataType(DataType.Password)]
        [Display(Name = "Password")]
        public string Password { get; set; }

        [DataType(DataType.Password)]
        [Display(Name = "Confirm password")]
        [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
        public string ConfirmPassword { get; set; }
    }

To check username availability:


 [AllowAnonymous]
        public JsonResult IsUserAvailable(string userName)
        {
            bool status = !WebSecurity.UserExists(userName); 
            return Json(new {result =status});
        }

AngularJS Controller:

Add a new javascript file(SignUpController.js) and add following:


var app = angular.module('validation', []);
app.controller('SignUpController', function ($scope,$http) {
    $scope.person = {};
    $scope.sendForm = function () {
        $http({
            method: 'POST',
            url: 'SignUp',
            data: $scope.person 
        }).success(function (data, status, headers, config) {
            $scope.message = '';
            if (data.success == false) {
                var str = '';
                for (var error in data.errors) {
                   str += data.errors[error] + '\n';
                }
                $scope.message = str;
            }
            else {
                $scope.message = 'Saved Successfully';               
                $scope.person = {};
            }
        }).error(function (data, status, headers, config) {                      
            $scope.message = 'Unexpected Error';
        });
    };    
});

In above code, validation module is created and SignUpController is defined. sendForm method is used to post form data to SignUp action.

Lets create a directive to call "IsUserAvailable" action to check whether username is available.


app.directive('ngUnique', ['$http', function (async) {
    return {
        require: 'ngModel',
        link: function (scope, elem, attrs, ctrl) {

            elem.on('blur', function (evt) {
                scope.$apply(function () {                   
                    var val = elem.val();
                    var req = { "userName": val }
                    var ajaxConfiguration = { method: 'POST', url: 'IsUserAvailable', data: req };
                    async(ajaxConfiguration)
                        .success(function(data, status, headers, config) {									
                            ctrl.$setValidity('unique', data.result);
                        });
                });
            });
        }
    }
}]);

View:

Right click on SignUp action in AccountController and Add View without layout, add jquery, angularjs and SignUpController references.


 <style type="text/css">
        label
       {           
           display:block;
       }
        input.ng-invalid.ng-dirty
        {
            background-color: #FA787E;
        }

        input.ng-valid.ng-dirty
        {
            background-color: #78FA89;
        }

        .invalid,.error
        {
            color: red;
            margin-top: 10px;
        }
    </style>
    <script src="~/Scripts/jquery-1.8.2.min.js"></script>
    <script src="~/Scripts/angular.min.js"></script>
    <script src="~/Scripts/SignUpController.js"></script>

 <div data-ng-app="validation">
        <form name="mainForm" data-ng-submit="sendForm()" data-ng-controller="SignUpController" novalidate>

data-ng-app="validation": to define module name

data-ng-controller="SignUpController": to define controller name

novalidate in form tag: to avoid HTML5 validations

data-ng-submit="sendForm()": to call sendForm method on submit.

Username Validations:

			<div>
                <label for="userName">User Name</label>
                <input id="userName" name="userName" type="text" data-ng-model="person.UserName" data-ng-pattern="/^[a-zA-Z0-9]{4,10}$/" 
                    ng-unique required />
                <span class="error" data-ng-show="mainForm.userName.$error.required">*</span>
                <span class="error" data-ng-show="mainForm.userName.$error.pattern">Invalid user name.</span>
                <span class="error" data-ng-show="mainForm.userName.$error.unique">Username already exists.</span>
            </div>

To check username avaiability ng-unique directive is used. Also pattern matching and required validations are applied.

When user enters username then ngUnique directive will call IsUserAvailable server action which returns result in true/false format.

Password Validations:

<div>
                <label for="password">Password</label>
                <input id="password" name="password" type="password" data-ng-model="person.Password" data-ng-minlength="6" required />
                <span class="error" data-ng-show="mainForm.password.$error.required">*</span>
                <span class="error" data-ng-show="mainForm.password.$error.minlength">Minimum 6 characters are required.</span>
            </div>
            <div>
                <label for="confirmPassword">Confirm Password</label>
                <input id="confirmPassword" name="confirmPassword" type="password" data-ng-model="person.ConfirmPassword" required />
                <span class="error" data-ng-show="mainForm.password.$error.required">*</span>
                <span class="error" data-ng-show="(mainForm.password.$dirty && mainForm.confirmPassword.$dirty) && (person.Password != person.ConfirmPassword)">Password mismatched</span>
            </div>

Others:


 <div>
                <input type="checkbox" data-ng-model="agreedToTerms" name="agreedToTerms" id="agreedToTerms" required />
                <label for="agreedToTerms" style="display:inline">I agree to the terms</label>
                <span class="error" data-ng-show="mainForm.agreedToTerms.$error.required">*</span>
            </div>
			 <div>
                <button type="submit"  data-ng-disabled="mainForm.$invalid" >Submit</button>
            </div>
             <div id="errorMessages" class="error">{{message}}</div>    
        </form>
    </div>

By default, Submit button is disabled. It will be enabled on all valid entries.

angularjs validation

Conclusion:

We have used AngularJS to implement form validations including username availability check in ASP.NET MVC. You can DOWNLOAD the complete source code in my this post.

Hope, It helps.