Rashim's Blog

Date range custom validation in Angular JS

Posted on: August 24, 2014

Getting instant response on the error in an input gives the user a better familiarity on how to precise it. Validation service is very handy to do that, and almost all controls have their own validation service. But sometime we require developing our own validation service to notify user that what input it might require, and it is very easy to inject our own validation to any control using Angular JS. Today I am going to introduce you with such custom validation technique using angular JS and its feature sets.

When we work with the date field we might be in situation to validate a date range that is to say that one date should be less than other date or vice versa. To implement such functionality I have written a small directive which provides this competence to us.

The following directive could be used to check that the date is lower than other date,

 
app.directive('dateLowerThan', ["$filter", function ($filter) {
    return {
        require: 'ngModel',
        link: function (scope, elm, attrs, ctrl) {           
            var validateDateRange = function (inputValue) {
                var fromDate = $filter('date')(inputValue, 'short');
                var toDate = $filter('date')(attrs.dateLowerThan, 'short');
                var isValid = isValidDateRange(fromDate, toDate);
                ctrl.$setValidity('dateLowerThan', isValid);
                return inputValue;
            };

            ctrl.$parsers.unshift(validateDateRange);
            ctrl.$formatters.push(validateDateRange);
            attrs.$observe('dateLowerThan', function () {
                validateDateRange(ctrl.$viewValue);
            });
        }
    };
}]);
 

Here we see that there are two new things: $parser and $formatters. While we need to write a custom validation we have to write a directive which would be dependent on the ng-model directive, and $parsers and $formatters is used to hook up the custom validation logic. When the value in the control is modified the functions added to $parsers are called, and the functions added to $formatters are invoked when the model is modified in the code.The $formatters are useful when there is a possibility of the value getting changed from the code. You will get an better idea if you go through this link

Same way, the following directive could be used to check whether a date is greater than other,

 
app.directive('dateGreaterThan', ["$filter", function ($filter) {
    return {
        require: 'ngModel',
        link: function (scope, elm, attrs, ctrl) {            
            var validateDateRange = function (inputValue) {
                var fromDate = $filter('date')(attrs.dateGreaterThan, 'short');
                var toDate = $filter('date')(inputValue, 'short');
                var isValid = isValidDateRange(fromDate, toDate);
                ctrl.$setValidity('dateGreaterThan', isValid);
                return inputValue;
            };

            ctrl.$parsers.unshift(validateDateRange);
            ctrl.$formatters.push(validateDateRange);
            attrs.$observe('dateGreaterThan', function () {
                validateDateRange(ctrl.$viewValue);

            });
        }
    };
}]);
 

The utility function that has been used here,

 
var isValidDate = function (dateStr) {
    if (dateStr == undefined)
        return false;
    var dateTime = Date.parse(dateStr);

    if (isNaN(dateTime)) {
        return false;
    }
    return true;
};

var getDateDifference = function (fromDate, toDate) {
    return Date.parse(toDate) - Date.parse(fromDate);
};

var isValidDateRange = function (fromDate, toDate) {
    if (fromDate == "" || toDate == "")
        return true;
    if (isValidDate(fromDate) == false) {
        return false;
    }
    if (isValidDate(toDate) == true) {
        var days = getDateDifference(fromDate, toDate);
        if (days < 0) {
            return false;
        }
    }
    return true;
};
 

And finally the module and controller,

 
var app = angular.module("Main_app", ['ui.bootstrap']);

app.controller("MainController", ["$scope", function ($scope) {
    var currentDate = new Date();
    $scope.FromDate = new Date();
    $scope.ToDate = currentDate.setDate(currentDate.getDate() + 1);
    $scope.dateOptions = {
        formatYear: 'yy',
        startingDay: 1
    };
    $scope.formats = ['dd-MMMM-yyyy', 'yyyy/MM/dd', 'dd.MM.yyyy', 'shortDate'];
    $scope.format = $scope.formats[0];
}]);
 

Files that you need to include,

angular.min.js

jquery.min.js

jquery-ui.min.js

ui-bootstrap.min.js

ui-bootstrap-tpls.min.js

And in html body you could use this directive like the way,


<div ng-controller="MainController">
        <form name="frmDateRange" novalidate>
            <div style="height: 400px">
                <div class="col-md-12 marginBottom15">
                    <label class="col-md-3 control-label">
                        From date
                    </label>
                    <div class="col-md-5">
                        <input type="text"
                            name="fromDate"
                            class="form-control"
                            datepicker-popup="{{format}}"
                            ng-model="FromDate"
                            datepicker-options="dateOptions"
                               required 
                            date-lower-than="{{ToDate| date:'short'}}" />
                    </div>
                    <div class="col-md-4 offset0">
                        <span 
                            ng-show="frmDateRange.fromDate.$error.required && 
                            !frmDateRange.fromDate.$pristine">
                            Invalid or Empty from date
                        </span>
                        <span
                            ng-show="frmDateRange.fromDate.$error.dateLowerThan">
                            From date must be lower than To date
                        </span>
                    </div>
                </div>
                <div class="col-md-12 marginBottom15">
                    <label class="col-md-3 control-label">
                        To date
                    </label>
                    <div class="col-md-5">
                        <input type="text"
                            name="endDate"
                            class="form-control"
                            datepicker-popup="{{format}}"
                            ng-model="ToDate"
                            min="FromDate"
                            datepicker-options="dateOptions"
                               required 
                            date-greater-than="{{FromDate| date:'short'}}" />
                    </div>
                    <div class="col-md-4 offset0">
                        <span 
                            ng-show="frmDateRange.endDate.$error.required 
                            && !frmDateRange.endDate.$pristine">
                            Invalid or Empty to date
                        </span>
                        <span 
                            ng-show="frmDateRange.endDate.$error.dateGreaterThan">
                            To date must be greater than from date
                        </span>
                    </div>
                </div>
            </div>
        </form>
    </div>
 

That’s it. Now play with this. The source code is available here.

Advertisements

4 Responses to "Date range custom validation in Angular JS"

plz help us to find the validation for datepicker in bootstrap without using jquery

nathi maltu bav try karyuuu

Hi,
This is Anvesh V, I’m impressed with your work. But, It seemed a little difficult to download and run the app. I have an advice for you. You can preview your app using many Online Editors like Plunker , JSFiddle , Editey and many more.

Excellent! I have used your work. Thank you

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: