Angularjs jQuery UI Datepicker disable dates conditionally

angularjs datepicker example/demo angularjs datepicker directive angularjs datepicker date format angularjs datepicker bootstrap angularjs calendar picker start date end date validation

Angularjs jquery calendar with minimum code to attach datepicker, how to extend to restrict the dates from a particular day, month or year, how to make calendar to validate start and end date from one control to other after user selection, how to format date before rendering or how to disable datepicker with the help of angular ngDisabled properties are some of the common points we are going to discuss in this article, please us the plunker to check the feature

1. Minimum code to add datepicker

If we want to add the datepicker to any text box we need a directive, let's see the minimum code we need to add a datepicker

app.directive('datePicker', function(){
    return{
      restrict: 'A',
      require: 'ngModel',
      link: function(scope, elm, attr, ctrl){           
        elm.datepicker({
          autoSize: true,
          changeYear: true,
          changeMonth: true,
          dateFormat: attr["dateformat"] || 'mm/dd/yy',
          showOn: 'button',
          buttonText: '<i class="glyphicon glyphicon-calendar"></i>',          
          onSelect: function (valu) {
            scope.$apply(function () {
                ctrl.$setViewValue(valu);
            });
            elm.focus();
          }           
        });
       }
    }
});

Let's see what we are doing here:

  • changeYear: true: allow to change the year by using dropdown inside the datepicker
  • changeMonth: true: allow to change the month by using dropdown inside the datepicker
  • dateFormat: user can set it by using dateformat attribute otherwise by default it will use mm/dd/yy format e.g 01/02/2018
  • buttonText: we use the bootstrap calender icon
  • onSelect: set the model value by using the apply

In this code there is no validation but it will work smooth to select the date by using datepicker, here is the HTML for our first example

<div class='col-xs-6'>
  <label>Start Date</label>
  <input type=text date-picker 
    placeholder='MM/DD/YYYY' 
    maxlength="10" 
    ng-required='true'
    class='form-control' 
    ng-model='model1.startDate'>
</div>
<div class='col-xs-6'>
  <label>End Date</label>
  <input type=text  date-picker 
      placeholder='MM/DD/YYYY' 
      maxlength="10" 
      ng-required='true'
      class='form-control' 
      ng-model='model1.endDate'>
</div>

So far so good, but in most of the cases we need to restrict the past or future date, so we need min and max validation

2. Min & Max Date Restrinction

To min and max restriction we will use the same jquery guidelines, let's have a look what jQuery provides

To add/reduce days/month/year

minDate: '+10D' // 10 days from today (future)
minDate: '-10D' // 10 days from today (past)
minDate: '+10M' // 10 months from today (future)
minDate: '-10M' // 10 months from today (past)
minDate: '+10Y' // 10 years from today (future)
minDate: '-10Y' // 10 years from today (past)

Similarly we can use for maxDate, for more information see the jquery documentation

We can also use the combination of year month and day like "+1Y +2M +5D" etc or we can use a date as well, which we will see in our next section.

All these logics should be applied on calendar before showing the calendar, so let's add the code for it:

In our directive add following code after onSelect function:

beforeShow: function(){
    if(attr["minDate"] != null)
        $(elm).datepicker('option', 'minDate', attr["minDate"]);

    if(attr["maxDate"] != null )
        $(elm).datepicker('option', 'maxDate', attr["maxDate"]);
}

Let's say we want start date in past one month up today and end date from today to one month then, add following attribute in start and end text box html respectively, run and see the result, our calendar will be disabled for other dates (simple):

min-date='-30D' max-date='+0D'
min-date='+0D' max-date='+1M'

3. Dependent Start & End Date Restriction

In most of the cases we need dependent start and end date, to say, expiry date must not be less than manufacturing date means start date must not be greater than end date or end date must not be less than start date etc.

We don't need to add any extra code for this but we can use our min-date and max-date attribute

// in start date text box 
max-date='{{model3.endDate}}'
// in end date text box
min-date='{{model3.startDate}}'

When you will open any text box first time, there would not be any restriction, say, first we open the end date calendar and it allow us to select any date, once we select any date our start date cannot allow to select any date greater than end date and vise versa.

You might ask, if I want to allow only the future date then? Right, you can use this by putting the min-date='+0D' in your start date text box, try this and select past date first from end date and then try to select any start date and see the magic.

Same logic you can apply for future date by putting max date in our end date text box max-date='+0D'.

Here is the complete code for this datepicker:

<div class='col-xs-6'>
  <label>Start Date</label>
  <input type=text date-picker 
    placeholder='MM/DD/YYYY' 
    maxlength="10" 
    ng-required='true'
    class='form-control' 
    ng-model='model3.startDate'
    max-date='{{model3.endDate}}'>
</div>
<div class='col-xs-6'>
  <label>End Date</label>
  <input type=text  date-picker 
      placeholder='MM/DD/YYYY' 
      maxlength="10" 
      ng-required='true'
      class='form-control' 
      ng-model='model3.endDate'
      min-date='{{model3.startDate}}'>
</div>

4. Format Date On Load

When we get date from database we get something like this 2018-01-17T17:30:49-0300 or some times string like this 01-17-2018, let's put these values on our model and see how it looks in our datepicker?

$scope.model4 = {
  startDate: '2018-01-17T17:30:49-0300',
  endDate: '01-17-2018'
}

You will notice, it shows whatever we have on our model, right? So how to format it when we load the page or user do the copy and paste?

Add following lines in our directive, inside the link function:

ctrl.$formatters.unshift(function(value) {
  if(value && moment(value).isValid()){
       return moment(new Date(value)).format('MM/DD/YYYY');
  }
  return value;
})

Note here we use momentjs to check if the provided date is valid or not and format date in my format MM/DD/YYYY. See the last line return value;, we check the value if not a valid value, don't format it just use it whatever it is. If you want you can clear the value if it is not a valid value, it's up to your need.

Now run the application and see both our date will show 01/17/2018, that's what we want.

5. Disable Datepicker icon with ng-disabled

If text box is disabled calendar should also be disabled. Try to get the answer from web, we get many different ways but nothing works :). Let's create the model like model5:

$scope.model5 = {
  startDate: null,
  endDate: null,
  disabled: false
}

Now bind the dates and checkbox to switch between true and false, note the change in text box attribute ng-disabled='model5.disabled' to disable the text box:

<div class='col-xs-5'>
  <label>Start Date</label>
  <input type=text date-picker 
    placeholder='MM/DD/YYYY' 
    maxlength="10" 
    ng-required='true'
    class='form-control'
    ng-disabled='model5.disabled'
    ng-model='model5.startDate'>
</div>
<div class='col-xs-5'>
  <label>End Date</label>
  <input type=text  date-picker 
      placeholder='MM/DD/YYYY' 
      maxlength="10" 
      ng-required='true'
      class='form-control' 
      ng-disabled='model5.disabled'
      ng-model='model5.endDate'>
</div>
<div class='col-xs-2'>
  <label>
    <input type='checkbox'
      ng-click='model5.disabled = !model5.disabled'/> Disable
  </label>
</div>  

Click on checkbox to disable the text box and click on calendar, we will be able to change the date. so disabling the text box is not enough, we need to disable the calendar as well.

jQuery Datepicker document says to disable the calendar use following code:

 $("#somdId").datepicker( "option", "disabled", true );

So when this code need to be executed, at the time of initializing the page or any time, every one will have different answer. Take our previous example it is dynamic, so it's better enable or disable dynamically because in some cases we need to disable the control conditionally.

We will add a watch to check the ng-disabled value of control where we used our directive, add following code in our directive:

scope.$watch(attr.ngDisabled, function (newVal) {
  if(newVal === true)
    $(elm).datepicker("disable");
  else
    $(elm).datepicker("enable");
});

Not switch to disable mode and click on calendar icon, datepicker is also disabled and not opening our calendar any more.

We use some CSS to place the calendar icon in text box and show the red/green border for valid and invalid dates, here is what we used:

.ui-datepicker-trigger{
  position: absolute;
  margin-top: -28px;
  right:15px;
  border:none;
  background-color:transparent;
}

.ng-valid{
  border-left: 2px solid #090;
}
.ng-invalid{
  border-left: 2px solid #900;
}
Ali Adravi Having 13+ years of experience in Microsoft Technologies (C#, ASP.Net, MVC and SQL Server). Worked with Metaoption LLC, for more than 9 years and still with the same company. Always ready to learn new technologies and tricks.
  • angularjs
  • jquery
  • datepicker
  • validation
By Ali Adravi On 26 Dec, 17  Viewed: 1,873

Other blogs you may like

Angularjs powerful paging on table and searching with delay and demo

Paging on table is the basic requirement and most of us look for some grid so it can provide the complete feature of paging and sorting but in Angularjs it is so easy that anyone can achieve it by writing some code. I checked and found most of the available code give the paging feature in for 1 to... By Ali Adravi   On 14 Aug 2015  Viewed: 13,628

Angularjs Cascading Dropdown/Select with demo

Cascading dropdown with angularjs is easier than MVC and ASP.Net. In Angularjs ng-change is the best event to hook the function to get the second dropdown list items. In this article, we will try to fill the state dropdown on selection change of country and then fill the city dropdown on change... By Ali Adravi   On 06 Aug 2015  Viewed: 48,429

Angularjs CRUD with Web API, Entity Framework & Bootstrap modal popup part 2

Add/Edid Customer in Modal Popup --- In previous article we discussed how to search, delete and show detail of customer and contact list. In this article we will try to open the modal popup to add new customer and edit an existing customer record. I divided article in two parts because of the... By Ali Adravi   On 29 Jul 2015  Viewed: 17,427

Custom Directives in AngularJS with example and demo

Angularjs custom directives are the common to avoid the duplicate code, it is easy powerful and really nice. There are already too many directive have been created by experts but as a developer we need to write our own to achieve our specific goal. ng-model, ng-if, ng-show, ng-repeat all these are... By Ali Adravi   On 29 Jul 2015  Viewed: 3,886

Angularjs CRUD with Web API, Entity Framework & Bootstrap modal popup part 1

Search sort Insert update and delete are the basic features we need to learn first to learn any language, In this article we will try to create these features with Web API, bootstrap modal popup and ui.router. We will use enetity framework code first to save and retrieve data from database. We... By Ali Adravi   On 28 Jul 2015  Viewed: 28,855