DotNetCurry Logo

ASP.NET MVC Custom Validation using AngularJS Custom Directive

Posted by: Mahesh Sabnis , on 5/25/2015, in Category ASP.NET MVC
Views: 21386
Abstract: Implement custom validation in an ASP.NET MVC app using Custom Directive in AngularJS

AngularJS has a directive for almost any web application scenario, but it also allows you to extend directive functionality by creating your own custom directives.

During a recent AngularJS training that I was conducting for one of my clients, I was asked a query about asynchronous validation using Angular.js where the value entered in a TextBox had to be validated using logic executed on server side. I was also asked to implement this validation by setting an attribute for the UI element which accepts the value and then validates this value based on the server side logic. I thought of sharing this solution with my readers via this article.


Let us start by creating an ASP.NET Web API which will accept model data from the UI. This API will send an Employee Number to the server and check if it is already present. If the EmpNo is already present on the server a Validation error will be displayed, else the value will be accepted.

As already mentioned, Angular.js allows you to create Custom Directives which can help to create HTML Elements, Custom Attributes for validation, etc. Technically, a directive is defined as a function executed on a particular DOM element to enhance its functionality or behavior. The Directive plays an important role in providing DataBinding, Events, Validations, etc. If you are new to directives, check Working with AngularJS Views and Directives.

We can implement our custom validation using Custom Directive in AngularJS.

Step 1: Open the free Visual Studio 2013 Community Edition (or any other VS 2013/2015 edition of your choice)  and create a new ASP.NET MVC application. In this application, in the App_Data folder add a new Sql Server Database of name Application.mdf. In this database add a new EmployeeInfo table with the following schema:

CREATE TABLE [dbo].[EmployeeInfo] (
    [EmpNo]       INT          IDENTITY (1, 1) NOT NULL,
    [EmpName]     VARCHAR (50) NOT NULL,
    [DeptName]    VARCHAR (50) NOT NULL,
    [Designation] VARCHAR (50) NOT NULL,
    [Salary]      DECIMAL (18) NOT NULL,

Add some Test Data in this table.

Step 2: In the Models folder, add an ADO.NET Entity Framework of the name ApplicationEDMX. In the wizard, select Application.mdf file. Select EmployeeInfo table for mapping. This will generate the Table mapping with EmployeeInfo class in the project.

Step 3: In the Controllers folder, add a new ASP.NET Web API with Entity Framework. Name this Web API class as EmployeeInfoAPIController. Select EmployeeInfio Model class and ApplicationEntities as DataContext Class. This will generate action methods for Get, Post, Put and Delete. In this class, add the following method to check if the Employee is already present in the database.

/// <summary>
/// Method to Check if the Employee already present
/// </summary>
/// <param name="e"></param>
/// <returns></returns>
private bool CheckIfEmpExist(EmployeeInfo e)
    bool isExits = false;

    var Emp = db.EmployeeInfoes.Find(e.EmpNo);
    if (Emp != null)
        isExits = true;

    return isExits;

Step 4: Make the following changes in the PostEmployeeInfo() method (highlighted code)

// POST: api/EmployeeInfoAPI
public IHttpActionResult PostEmployeeInfo(EmployeeInfo employeeInfo)

    if (!ModelState.IsValid)
        return BadRequest(ModelState);

    if (CheckIfEmpExist(employeeInfo))
        return Conflict();


        return CreatedAtRoute("DefaultApi", new { id = employeeInfo.EmpNo }, employeeInfo);
    return Ok();

The above Post method checks if the Employee already exist, if yes the Conflict http status code will be returned.

Step 5: Using the NuGet Package manager add references to jQuery, Bootstrap and AngularJS.

Step 6: In the Scripts folder, add a new folder of the name MyScripts. In this folder, add a new JavaScipt file of the name logic.js. Add the following code in it:

var app;
(function () {
    app = angular.module('appmodule', []);

//The Directive for Custom Validation for the Attribute Directive
app.directive('requiredUniquevalue', function ($http) {
    return {
        require: 'ngModel',
        link: function (scope, element, attribute, ctrl) {
            scope.$watch(attribute.ngModel, function () {
                    method: 'POST',
                    url: '/api/EmployeeInfoAPI/' + attribute.requiredUniquevalue,
                    data: { 'EmpNo': attribute.requiredUniquevalue }
                }).success(function (res) {
                    if (res) {
                        ctrl.$setValidity('requiredUniquevalue', false);
                    } else {
                        ctrl.$setValidity('requiredUniquevalue', true);
                }).error(function (err) {
                    ctrl.$setValidity('requiredUniquevalue', false);

//The Controller
app.controller('appctrl', function ($scope) {
    $scope.Employee = {
        EmpNo: 0,
        EmpName: "",
        DeptName: "",
        Salary: "",
        Designation: "",

The above JavaScript code has the following bits and pieces:

  • An Angular module of name ‘appmodule’.
  • The custom directive of name requireUniquevalue. This accepts $http as dependency because we need to make a call to the WEB API to check whether the EmpNo is already present. The directive is set with the link property with the function accepting following parameters:
    • Scope: Defines the scope property to be checked for updates, to watch value changes.
    • Attribute: This accepts the attribute value set for the DOM element.
    • Element and ctrl: These are used to manage the execution of element bound to the controller’s scope for controlling the validity status. This uses $setValidity() function to validate the element.
  • The function set for the link property makes call to Web API and post the EmpNo to it. If the EmpNo exists, the $setValidity() will be false, else true.
  • The Angular Controller of name ‘appctrl’ used to declare the scope object which will be bound to UI.

Step 7: In the Controller folder, add an empty MVC controller of name EmployeeController and scaffold an empty index view from it.

Step 8: Add the following markup in the Index.cshtml

    ViewBag.Title = "Index";

<link href="~/Content/bootstrap.min.css" rel="stylesheet" />
<script src="~/Scripts/jquery-2.1.3.min.js"></script>
<script src="~/Scripts/bootstrap.min.js"></script>
<script src="~/Scripts/angular.min.js"></script>
<script src="~/Scripts/MyScripts/Logic.js"></script>
<div ng-app="appmodule">
    <div ng-controller="appctrl">
        <form novalidate role="form" name="frmEmployee">
            <table class="table table-condensed table-bordered table-striped">
                            <input type="text" name="EmpNo" ng-model="Employee.EmpNo"
                                   required-uniquevalue="{{Employee.EmpNo}}" />
                            <span class="help-block" ng-if="frmEmployee.EmpNo.$error.requiredUniquevalue && frmEmployee.EmpNo.$dirty">EmpNo is already Present</span>

In the above markup, the input tag is set with the name attribute as EmpNo. This element is applied with the attribute as required-uniquevalue, this is the custom validation directive created. This accepts EmpNo scope using angular expression as {{Employee.EmpNo}}. In the custom directive implementation, the link function calls scope.$watch() function to which required-uniquevalue attribute value is passed for validation.

Run the application and enter EmpNo in the TextBox, if the EmpNo is already present, the output will be as shown here:



Angular.js directives are useful to provide an easy implementation for domain specific validations. We saw how we could easily use in a server-side application built using ASP.NET MVC.

Download the entire source code of this article (Github)

Was this article worth reading? Share it with fellow developers too. Thanks!
Share on LinkedIn
Share on Google+
Further Reading - Articles You May Like!
Mahesh Sabnis is a DotNetCurry author and Microsoft MVP having over 17 years of experience in IT education and development. He is a Microsoft Certified Trainer (MCT) since 2005 and has conducted various Corporate Training programs for .NET Technologies (all versions). Follow him on twitter @maheshdotnet

Page copy protected against web site content infringement 	by Copyscape

Feedback - Leave us some adulation, criticism and everything in between!