bootstrap icon indicating copy to clipboard operation
bootstrap copied to clipboard

Datepicker add a option to disable days from previous/next month

Open schmitch opened this issue 10 years ago • 11 comments

Hello, currently the datepicker has no option to disable the dates from the previous and the next month, it will always print the 30., 31. or so from the date before and the 1., 2.

Another option would be that the date-disabled function has the current date so we could build a global option like that: http://stackoverflow.com/questions/22544118/angular-ui-datepicker-limiting-days-to-one-month

schmitch avatar Jun 15 '15 09:06 schmitch

I think, with a bit of tinkering, that you can achieve this by implementing a custom template for the datepicker.

rvanbaalen avatar Jun 19 '15 02:06 rvanbaalen

yea rvanbaalen is right.. i did this and it worked great.. I also modified the more of the custom template to get the look I wanted too. attached is what i was able to get.. screen shot 2016-01-29 at 1 22 53 pm

sandman45 avatar Jan 29 '16 20:01 sandman45

@sandman45 : Can you please share the template you used to achieve this?

Thanks

maverick09 avatar Feb 25 '16 17:02 maverick09

+1 for the template @sandman45

jonwinton avatar Mar 11 '16 15:03 jonwinton

@maverick09 Ok so this isn't a great way to solve it, but it worked for me:

The issue is that the activeDate property on the Datepicker's controller isn't easily accessible without going through a decorator to modify the directive. But the activeDate property is available in the template using `{{datepicker.activeDate}}.

In my custom template for the day picker I but an ngIf on the <button> element:

<button type="button" class="uib-daypicker__date"
             uib-is-class="'btn-info' for selectedDt,'active' for activeDt on dt"
             ng-click="select(dt.date)"
             ng-disabled="::dt.disabled"
             ng-if="datepicker.activeDate.getMonth() === dt.date.getMonth()"
             tabindex="-1">
             <span ng-class="::{'text-muted': dt.secondary, 'text-info': dt.current}">{{::dt.label}}</span>
</button>

I didn't put the ngIf on the <td> because that would collapse the space for each day that wouldn't be rendered and make the days and dates not line up. To make sure these elements were ignored I slapped a ng-aria-hidden="{{datepicker.activeDate.getMonth() !== dt.date.getMonth()}}" on the <td> just to hide the empty cells from screen readers.

It works but it's kind of dirty :/ If you're not going to go the decorator route this will work for you. Just make sure you create your own custom template.

Hope that helps!

jonwinton avatar Mar 11 '16 20:03 jonwinton

In my front of view the best way to do this it's put this setting into directive "template-url="yourWayToDatepickerTpl". Just like this

<div uib-datepicker ng-model="dt" class="well well-sm" template-url="assets/components/angular/datepickerCustomTmpls/index.html"
                                     datepicker-options="{showWeeks: false, formatDayTitle: 'LLLL'}"></div>

And then in "datepickerCustomTmpls/index.html" :

<div ng-switch="datepickerMode">
      <div uib-daypicker template-url="assets/components/angular/datepickerCustomTmpls/day.html" ng-switch-when="day" tabindex="0" class="uib-daypicker"></div>
      <div uib-monthpicker template-url="assets/components/angular/datepickerCustomTmpls/month.html" ng-switch-when="month" tabindex="0" class="uib-monthpicker"></div>
      <div uib-yearpicker template-url="assets/components/angular/datepickerCustomTmpls/year.html" ng-switch-when="year" tabindex="0" class="uib-yearpicker"></div>
</div>

Then you can control daypicker or monthpicker or yearpicker in your templates "datepickerCustomTmpls/day.html", "datepickerCustomTmpls/month.html", "datepickerCustomTmpls/year.html". If you dont want use custom tmpl for year (for example), just delete template-url setting in uib-yearpicker

<div uib-yearpicker template-url="assets/components/angular/datepickerCustomTmpls/year.html" ng-switch-when="year" tabindex="0" class="uib-yearpicker"></div>

Code of day, month and year tmpls for @maverick09 : Day, i'm already added @jonwinton solution (ng-if)

<table role="grid" aria-labelledby="{{::uniqueId}}-title" aria-activedescendant="{{activeDateId}}">
    <thead>
    <tr>
        <th>
            <button type="button" class="btn btn-default btn-sm pull-left uib-left" ng-click="move(-1)" tabindex="-1"><i
                    class="glyphicon glyphicon-chevron-left"></i></button>
        </th>
        <th colspan="{{::5 + showWeeks}}">
            <button id="{{::uniqueId}}-title" role="heading" aria-live="assertive" aria-atomic="true" type="button"
                    class="btn btn-default btn-sm uib-title" ng-click="toggleMode()"
                    ng-disabled="datepickerMode === maxMode" tabindex="-1"><strong>{{title}}</strong></button>
        </th>
        <th>
            <button type="button" class="btn btn-default btn-sm pull-right uib-right" ng-click="move(1)" tabindex="-1">
                <i class="glyphicon glyphicon-chevron-right"></i></button>
        </th>
    </tr>
    <tr>
        <th ng-if="showWeeks" class="text-center"></th>
        <th ng-repeat="label in ::labels track by $index" class="text-center ">
            <small aria-label="{{::label.full}}">{{::label.abbr}}</small>
        </th>
    </tr>
    </thead>
    <tbody>
    <tr class="uib-weeks" ng-repeat="row in rows track by $index">
        <td ng-if="showWeeks" class="text-center h6"><em>{{ weekNumbers[$index] }}</em></td>
        <td ng-repeat="dt in row" class="uib-day text-center " role="gridcell"
            id="{{::dt.uid}}"
            ng-class="::dt.customClass">
            <button type="button" class="btn btn-default btn-sm"
                    uib-is-class="
                        'btn-info' for selectedDt,
                            'active' for activeDt
                               on dt"
                    ng-click="select(dt.date)"
                    ng-disabled="::dt.disabled"
                    ng-if="datepicker.activeDate.getMonth() === dt.date.getMonth()"
                    tabindex="-1"><span ng-class="::{'text-muted': dt.secondary, 'text-info': dt.current}">{{::dt.label}}</span>
            </button>
        </td>
    </tr>
    </tbody>
</table>

Month:

<table role="grid" aria-labelledby="{{::uniqueId}}-title" aria-activedescendant="{{activeDateId}}">
    <thead>
    <tr>
        <th>
            <button type="button" class="btn btn-default btn-sm pull-left uib-left" ng-click="move(-1)" tabindex="-1"><i
                    class="glyphicon glyphicon-chevron-left"></i></button>
        </th>
        <th colspan="{{::yearHeaderColspan}}">
            <button id="{{::uniqueId}}-title" role="heading" aria-live="assertive" aria-atomic="true" type="button"
                    class="btn btn-default btn-sm uib-title" ng-click="toggleMode()"
                    ng-disabled="datepickerMode === maxMode" tabindex="-1"><strong>{{title}}</strong></button>
        </th>
        <th>
            <button type="button" class="btn btn-default btn-sm pull-right uib-right" ng-click="move(1)" tabindex="-1">
                <i class="glyphicon glyphicon-chevron-right"></i></button>
        </th>
    </tr>
    </thead>
    <tbody>
    <tr class="uib-months" ng-repeat="row in rows track by $index">
        <td ng-repeat="dt in row" class="uib-month text-center" role="gridcell"
            id="{{::dt.uid}}"
            ng-class="::dt.customClass">
            <button type="button" class="btn btn-default"
                    uib-is-class="
              'btn-info' for selectedDt,
              'active' for activeDt
              on dt"
                    ng-click="select(dt.date)"
                    ng-disabled="::dt.disabled"
                    tabindex="-1"><span ng-class="::{'text-info': dt.current}">{{::dt.label}}</span></button>
        </td>
    </tr>
    </tbody>
</table>

Year:

<table role="grid" aria-labelledby="{{::uniqueId}}-title" aria-activedescendant="{{activeDateId}}">  <thead>
       <tr>
          <th><button type="button" class="btn btn-default btn-sm pull-left uib-left" ng-click="move(-1)" tabindex="-1"><i class="glyphicon glyphicon-chevron-left"></i></button></th>
          <th colspan="{{::columns - 2}}"><button id="{{::uniqueId}}-title" role="heading" aria-live="assertive" aria-atomic="true" type="button" class="btn btn-default btn-sm uib-title" ng-click="toggleMode()" ng-disabled="datepickerMode === maxMode" tabindex="-1"><strong>{{title}}</strong></button></th>
          <th><button type="button" class="btn btn-default btn-sm pull-right uib-right" ng-click="move(1)" tabindex="-1"><i class="glyphicon glyphicon-chevron-right"></i></button></th>
        </tr>
     </thead>
     <tbody>
       <tr class="uib-years" ng-repeat="row in rows track by $index">
         <td ng-repeat="dt in row" class="uib-year text-center" role="gridcell"
           id="{{::dt.uid}}"
           ng-class="::dt.customClass">
           <button type="button" class="btn btn-default"
             uib-is-class="
               'btn-info' for selectedDt,
               'active' for activeDt
               on dt"
             ng-click="select(dt.date)"
             ng-disabled="::dt.disabled"
             tabindex="-1"><span ng-class="::{'text-info': dt.current}">{{::dt.label}}</span></button>
         </td>
       </tr>
     </tbody>
   </table>

It's my first answer on github) Dont kick me)

MrHantLP avatar Aug 10 '16 01:08 MrHantLP

@jonwinton How do you access the activeDate property with a decorator? I am trying to hook my own functionality onto the change of month like is discussed here: http://stackoverflow.com/questions/26928861/angular-ui-bootstrap-datepicker-is-there-a-way-of-detecting-when-the-month

function DatepickerDirectiveDecorator($delegate) {
    var directive = $delegate[0];
    var link = directive.link;

    directive.compile = function() {
      return function(scope, element, attrs, ctrl) {
        link.apply(this, arguments);

        scope.$watch(function() {
          return ctrl[0].activeDate.getTime();
        }, function() {
          console.log('switched')
        });
      }
    };

    return $delegate;
  }

However activeDate like I'm using it here always seems to be undefined.

jkelso07 avatar Aug 18 '16 16:08 jkelso07

hi sir. I am using angularj Bootrap DatePicker. i have issue occur . when i am edit date. the can't show on UI but they can avilible on Backend. this Url that i am using DatePicker (https://plnkr.co/edit/?p=preview)

kindly see the Attachment capture taee

MuhammadTayyeb avatar Aug 26 '16 23:08 MuhammadTayyeb

Cannot say what exactly you are looking but might be this link can help you:

http://www.advancesharp.com/blog/1224/angularjs-jquery-ui-datepicker-for-any-condition

AliAdravi avatar Dec 26 '17 23:12 AliAdravi

No need to use a custom template. Use the custom class option.

<div uib-datepicker ng-model="$ctrl.selected" datepicker-options="{ customClass: $ctrl.getCustomClass }"></div>

then in your controller\component

getCustomClass (date, mode) {
  let customClass = '';
  if (mode === 'day') {
    let monthToCheck = date.getMonth();

    // 'this' refers to the datepicker's scope so you can get access to all it's goodies
    let activeMonth = this.datepicker.activeDate.getMonth();

    if (monthToCheck === activeMonth) {
       customClass = 'datepicker-day-current-month';
    }
  }

  return customClass;
}

And now in your app's css you can do something like this:

.uib-datepicker .uib-day:not(.datepicker-day-current-month) {
  visibility: hidden;
}

tinyfly avatar Apr 25 '18 21:04 tinyfly

I created this revision so that I could 'hear' the active date change. Hope it works for you. My change

eantoranz avatar May 02 '18 00:05 eantoranz