Sep 19, 2013

Displaying ModelState Errors with AngularJS in ASP.NET MVC

This article explains how to display all ModelState errors (like validationsummary) in ASP.NET MVC using AngularJS.

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 case of error, We are using LINQ to get all errormessages as follows:

errors = ModelState.Keys.SelectMany(k => ModelState[k].Errors) .Select(m => m.ErrorMessage).ToArray()

The inbuilt RegisterModel (in AccountModels) is used as argument of SignUp Post action.


 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; }
    }

AngularJS Controller:


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

In above code, error messages are assigned to errors model like below in case of errors.

if (data.success === false) {

$scope.errors = data.errors;

}

View:

For the demo purpose, I am NOT doing client side validation in SignUp view. Refer following article for client side validation in AngularJS:

Username Availability Check with AngularJS in ASP.NET MVC


 <div data-ng-app="validation">
            
            <form name="mainForm" data-ng-submit="sendForm()" data-ng-controller="SignUpController" novalidate>
                <div class="error">{{message}}</div>
                <div>
                    <label for="userName">User Name</label>
                    <input id="userName" name="userName" type="text" data-ng-model="person.UserName" />
                </div>
                <div>
                    <label for="password">Password</label>
                    <input id="password" name="password" type="password" data-ng-model="person.Password" />
                </div>
                <div>
                    <label for="confirmPassword">Confirm Password</label>
                    <input id="confirmPassword" name="confirmPassword" type="password" data-ng-model="person.ConfirmPassword" />
                </div>
                <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>
                </div>
                <div>
                    <button type="submit" data-ng-disabled="mainForm.$invalid">Submit</button>
                </div>                
                <ul>
                    <li id="errorMessages" class="error" data-ng-repeat="error in errors">{{error}}</li>
                </ul>
            </form>
        </div>

To display all error messages, the following code is used


 <li id="errorMessages" class="error" data-ng-repeat="error in errors">{{error}}</li>
Conclusion:

It's a sample about how to get all ModelState errors using LINQ on server side, pass it as json, display it using AngularJS Model.

Hope, It helps.