angular-ui / bootstrap

PLEASE READ THE PROJECT STATUS BELOW. Native AngularJS (Angular) directives for Bootstrap. Smaller footprint (20kB gzipped), no 3rd party JS dependencies (jQuery, bootstrap JS) required. Please read the README.md file before submitting an issue!
http://angular-ui.github.io/bootstrap/
MIT License
14.29k stars 6.73k forks source link

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

Open schmitch opened 9 years ago

schmitch commented 9 years ago

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

rvanbaalen commented 9 years ago

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

sandman45 commented 8 years ago

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

maverick09 commented 8 years ago

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

Thanks

jonwinton commented 8 years ago

+1 for the template @sandman45

jonwinton commented 8 years ago

@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!

MrHantLP commented 8 years ago

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)

jkelso07 commented 8 years ago

@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.

MuhammadTayyeb commented 8 years ago

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

AliAdravi commented 6 years ago

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

tinyfly commented 6 years ago

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;
}
eantoranz commented 6 years ago

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