diff --git a/demo/src/app/components/+datepicker/datepicker-section.list.ts b/demo/src/app/components/+datepicker/datepicker-section.list.ts index 5ce0f5337e..b8446f75c7 100644 --- a/demo/src/app/components/+datepicker/datepicker-section.list.ts +++ b/demo/src/app/components/+datepicker/datepicker-section.list.ts @@ -10,6 +10,7 @@ import { DemoDatePickerConfigObjectComponent } from './demos/config-object/confi import { DemoDatePickerCustomFormatComponent } from './demos/custom-format/custom-format'; import { DemoDatepickerDateInitialStateComponent } from './demos/date-initial-state/date-initial-state'; import { DemoDatepickerDaysDisabledComponent } from './demos/disable-days/disable-days'; +import { DemoDatepickerDatesDisabledComponent } from './demos/disable-dates/disable-dates'; import { DemoDatepickerInlineComponent } from './demos/inline-datepicker/inline-datepicker.component'; import { DemoDatepickerDisabledComponent } from './demos/disabled/disabled.component'; import { DemoDatepickerFormsComponent } from './demos/forms/forms.component'; @@ -173,6 +174,16 @@ export const demoComponentContent: ContentSection[] = [ Sunday is considered the first day of the week and thus has the value 0

`, outlet: DemoDatepickerDaysDisabledComponent }, + { + title: 'Dates disabled', + anchor: 'dates-disabled', + component: require('!!raw-loader?lang=typescript!./demos/disable-dates/disable-dates.ts'), + html: require('!!raw-loader?lang=markup!./demos/disable-dates/disable-dates.html'), + description: ` +

You can set which dates should be disabled with datesDisabled

+

In the following example datesDisabled is set with an array to disable 2019-02-05 and 2019-02-09.

`, + outlet: DemoDatepickerDatesDisabledComponent + }, { title: 'Min-mode', anchor: 'min-mode', diff --git a/demo/src/app/components/+datepicker/demos/disable-dates/disable-dates.html b/demo/src/app/components/+datepicker/demos/disable-dates/disable-dates.html new file mode 100644 index 0000000000..cecab7c30e --- /dev/null +++ b/demo/src/app/components/+datepicker/demos/disable-dates/disable-dates.html @@ -0,0 +1,16 @@ +
+
+ +
+
+ +
+
diff --git a/demo/src/app/components/+datepicker/demos/disable-dates/disable-dates.ts b/demo/src/app/components/+datepicker/demos/disable-dates/disable-dates.ts new file mode 100644 index 0000000000..a79f324dff --- /dev/null +++ b/demo/src/app/components/+datepicker/demos/disable-dates/disable-dates.ts @@ -0,0 +1,12 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'demo-datepicker-datesdisabled', + templateUrl: './disable-dates.html' +}) +export class DemoDatepickerDatesDisabledComponent { + disabledDates = [ + new Date('2019-02-05'), + new Date('2019-02-09') + ]; +} diff --git a/demo/src/app/components/+datepicker/demos/index.ts b/demo/src/app/components/+datepicker/demos/index.ts index 33dcb5cffc..6f922d7989 100644 --- a/demo/src/app/components/+datepicker/demos/index.ts +++ b/demo/src/app/components/+datepicker/demos/index.ts @@ -9,6 +9,7 @@ import { DemoDatePickerCustomFormatComponent } from './custom-format/custom-form import { DemoDatepickerCustomTodayClassComponent } from './custom-today-class/custom-today-class.component'; import { DemoDatepickerDateInitialStateComponent } from './date-initial-state/date-initial-state'; import { DemoDatepickerDaysDisabledComponent } from './disable-days/disable-days'; +import { DemoDatepickerDatesDisabledComponent } from './disable-dates/disable-dates'; import { DemoDatepickerDisabledComponent } from './disabled/disabled.component'; import { DemoDatepickerFormsComponent } from './forms/forms.component'; import { DemoDatepickerHideOnScrollComponent } from './hide-on-scroll/hide-on-scroll'; @@ -41,6 +42,7 @@ export const DEMO_COMPONENTS = [ DemoDatePickerCustomFormatComponent, DemoDatepickerCustomTodayClassComponent, DemoDatepickerDateInitialStateComponent, + DemoDatepickerDatesDisabledComponent, DemoDatepickerDaysDisabledComponent, DemoDatepickerDisabledComponent, DemoDatepickerFormsComponent, diff --git a/demo/src/ng-api-doc.ts b/demo/src/ng-api-doc.ts index 1060ddf9a8..3070bffd38 100644 --- a/demo/src/ng-api-doc.ts +++ b/demo/src/ng-api-doc.ts @@ -676,6 +676,11 @@ export const ngdoc: any = { "type": "Date", "description": "

Initial value of datepicker

\n" }, + { + "name": "datesDisabled", + "type": "Date[]", + "description": "

Disable specific dates

\n" + }, { "name": "isDisabled", "type": "boolean", @@ -748,6 +753,11 @@ export const ngdoc: any = { "type": "string", "description": "

A selector specifying the element the datepicker should be appended to.\nCurrently only supports "body".

\n" }, + { + "name": "datesDisabled", + "type": "Date[]", + "description": "

Disable specific dates

\n" + }, { "name": "daysDisabled", "type": "number[]", @@ -862,6 +872,11 @@ export const ngdoc: any = { "type": "string", "description": "

Add class to current day

\n" }, + { + "name": "datesDisabled", + "type": "Date[]", + "description": "

Disable specific dates

\n" + }, { "name": "maxDate", "type": "Date", @@ -875,7 +890,7 @@ export const ngdoc: any = { { "name": "minMode", "type": "BsDatepickerViewMode", - "description": "

Defaut mode for all date pickers

\n" + "description": "

Default mode for all date pickers

\n" }, { "name": "rangeInputFormat", @@ -888,6 +903,11 @@ export const ngdoc: any = { "type": "boolean", "description": "

Makes dates from other months active

\n" }, + { + "name": "selectWeek", + "type": "boolean", + "description": "

Makes dates from other months active

\n" + }, { "name": "showWeekNumbers", "defaultValue": "true", @@ -929,6 +949,11 @@ export const ngdoc: any = { "type": "string", "description": "

A selector specifying the element the daterangepicker should be appended\nto. Currently only supports "body".

\n" }, + { + "name": "datesDisabled", + "type": "Date[]", + "description": "

Disable specific dates

\n" + }, { "name": "isDisabled", "type": "boolean", @@ -1666,6 +1691,10 @@ export const ngdoc: any = { "name": "onHover", "description": "" }, + { + "name": "onHoverWeek", + "description": "" + }, { "name": "onNavigate", "description": "" @@ -1940,7 +1969,7 @@ export const ngdoc: any = { "properties": [ { "name": "dropdownMenu", - "type": "Promise", + "type": "Promise>", "description": "

Content to be displayed as popover.

\n" } ] @@ -2953,11 +2982,6 @@ export const ngdoc: any = { "type": "boolean", "description": "

if true hours and minutes fields will be disabled

\n" }, - { - "name": "disabled", - "type": "boolean", - "description": "

if true hours and minutes fields will be disabled

\n" - }, { "name": "hourStep", "type": "number", @@ -3046,12 +3070,6 @@ export const ngdoc: any = { "type": "boolean", "description": "

if true hours and minutes fields will be disabled

\n" }, - { - "name": "disabled", - "defaultValue": "false", - "type": "boolean", - "description": "

if true hours and minutes fields will be disabled

\n" - }, { "name": "hourStep", "defaultValue": "1", diff --git a/src/chronos/public_api.ts b/src/chronos/public_api.ts index 244e63543c..fecc9e23e2 100644 --- a/src/chronos/public_api.ts +++ b/src/chronos/public_api.ts @@ -27,7 +27,7 @@ export { export { LocaleData } from './locale/locale.class'; -export { isAfter, isBefore, isDisabledDay } from './utils/date-compare'; +export { isAfter, isBefore, isDisabledDay, isSame } from './utils/date-compare'; export { isArray, isDateValid, isDate } from './utils/type-checks'; export { shiftDate, setFullDate } from './utils/date-setters'; export { endOf, startOf } from './utils/start-end-of'; diff --git a/src/datepicker/base/bs-datepicker-container.ts b/src/datepicker/base/bs-datepicker-container.ts index 8895a27e16..d5bb22739e 100644 --- a/src/datepicker/base/bs-datepicker-container.ts +++ b/src/datepicker/base/bs-datepicker-container.ts @@ -33,6 +33,9 @@ export abstract class BsDatepickerAbstractComponent { set daysDisabled(value: number[]) { this._effects.setDaysDisabled(value); } + set datesDisabled(value: Date[]) { + this._effects.setDatesDisabled(value); + } set isDisabled(value: boolean) { this._effects.setDisabled(value); diff --git a/src/datepicker/bs-datepicker-inline.component.ts b/src/datepicker/bs-datepicker-inline.component.ts index f32645dcd6..cb256269fb 100644 --- a/src/datepicker/bs-datepicker-inline.component.ts +++ b/src/datepicker/bs-datepicker-inline.component.ts @@ -42,6 +42,10 @@ export class BsDatepickerInlineDirective implements OnInit, OnDestroy, OnChanges * Maximum date which is available for selection */ @Input() maxDate: Date; + /** + * Disable specific dates + */ + @Input() datesDisabled: Date[]; /** * Emits when datepicker value has been changed */ @@ -103,6 +107,10 @@ export class BsDatepickerInlineDirective implements OnInit, OnDestroy, OnChanges this._datepickerRef.instance.maxDate = this.maxDate; } + if (changes.datesDisabled) { + this._datepickerRef.instance.datesDisabled = this.datesDisabled; + } + if (changes.isDisabled) { this._datepickerRef.instance.isDisabled = this.isDisabled; } @@ -116,7 +124,8 @@ export class BsDatepickerInlineDirective implements OnInit, OnDestroy, OnChanges value: this._bsValue, isDisabled: this.isDisabled, minDate: this.minDate || this.bsConfig && this.bsConfig.minDate, - maxDate: this.maxDate || this.bsConfig && this.bsConfig.maxDate + maxDate: this.maxDate || this.bsConfig && this.bsConfig.maxDate, + datesDisabled: this.datesDisabled || this.bsConfig && this.bsConfig.datesDisabled }); } diff --git a/src/datepicker/bs-datepicker.component.ts b/src/datepicker/bs-datepicker.component.ts index 4bdbcf4a14..0bab54dc78 100644 --- a/src/datepicker/bs-datepicker.component.ts +++ b/src/datepicker/bs-datepicker.component.ts @@ -100,6 +100,11 @@ export class BsDatepickerDirective implements OnInit, OnDestroy, OnChanges { * Disable Certain days in the week */ @Input() daysDisabled: number[]; + + /** + * Disable specific dates + */ + @Input() datesDisabled: Date[]; /** * Emits when datepicker value has been changed */ @@ -153,6 +158,10 @@ export class BsDatepickerDirective implements OnInit, OnDestroy, OnChanges { this._datepickerRef.instance.daysDisabled = this.daysDisabled; } + if (changes.datesDisabled) { + this._datepickerRef.instance.datesDisabled = this.datesDisabled; + } + if (changes.isDisabled) { this._datepickerRef.instance.isDisabled = this.isDisabled; } @@ -227,6 +236,7 @@ export class BsDatepickerDirective implements OnInit, OnDestroy, OnChanges { minDate: this.minDate || this.bsConfig && this.bsConfig.minDate, maxDate: this.maxDate || this.bsConfig && this.bsConfig.maxDate, daysDisabled: this.daysDisabled || this.bsConfig && this.bsConfig.daysDisabled, + datesDisabled: this.datesDisabled || this.bsConfig && this.bsConfig.datesDisabled, minMode: this.minMode || this.bsConfig && this.bsConfig.minMode }); } diff --git a/src/datepicker/bs-datepicker.config.ts b/src/datepicker/bs-datepicker.config.ts index 3e5611654d..d4a8e8e34e 100644 --- a/src/datepicker/bs-datepicker.config.ts +++ b/src/datepicker/bs-datepicker.config.ts @@ -23,6 +23,11 @@ export class BsDatepickerConfig implements DatepickerRenderOptions { maxDate?: Date; daysDisabled?: number[]; + + /** + * Disable specific dates + */ + datesDisabled?: Date[]; /** * Makes dates from other months active */ diff --git a/src/datepicker/bs-daterangepicker.component.ts b/src/datepicker/bs-daterangepicker.component.ts index e58928a366..bb8f77b1a6 100644 --- a/src/datepicker/bs-daterangepicker.component.ts +++ b/src/datepicker/bs-daterangepicker.component.ts @@ -102,6 +102,10 @@ export class BsDaterangepickerDirective * Maximum date which is available for selection */ @Input() maxDate: Date; + /** + * Disable specific dates + */ + @Input() datesDisabled: Date[]; /** * Emits when daterangepicker value has been changed */ @@ -150,6 +154,10 @@ export class BsDaterangepickerDirective this._datepickerRef.instance.maxDate = this.maxDate; } + if (changes.datesDisabled) { + this._datepickerRef.instance.datesDisabled = this.datesDisabled; + } + if (changes.isDisabled) { this._datepickerRef.instance.isDisabled = this.isDisabled; } @@ -205,7 +213,8 @@ export class BsDaterangepickerDirective value: this._bsValue, isDisabled: this.isDisabled, minDate: this.minDate || this.bsConfig && this.bsConfig.minDate, - maxDate: this.maxDate || this.bsConfig && this.bsConfig.maxDate + maxDate: this.maxDate || this.bsConfig && this.bsConfig.maxDate, + datesDisabled: this.datesDisabled || this.bsConfig && this.bsConfig.datesDisabled } ); } diff --git a/src/datepicker/engine/flag-days-calendar.ts b/src/datepicker/engine/flag-days-calendar.ts index e361f81661..17ed8289b3 100644 --- a/src/datepicker/engine/flag-days-calendar.ts +++ b/src/datepicker/engine/flag-days-calendar.ts @@ -13,13 +13,14 @@ import { shiftDate } from 'ngx-bootstrap/chronos'; -import { isMonthDisabled } from '../utils/bs-calendar-utils'; +import { isMonthDisabled, isDisabledDate } from '../utils/bs-calendar-utils'; export interface FlagDaysCalendarOptions { isDisabled: boolean; minDate: Date; maxDate: Date; daysDisabled: number[]; + datesDisabled: Date[]; hoveredDate: Date; selectedDate: Date; selectedRange: Date[]; @@ -63,7 +64,8 @@ export function flagDaysCalendar( options.isDisabled || isBefore(day.date, options.minDate, 'day') || isAfter(day.date, options.maxDate, 'day') || - isDisabledDay(day.date, options.daysDisabled); + isDisabledDay(day.date, options.daysDisabled) || + isDisabledDate(day.date, options.datesDisabled); const currentDate = new Date(); const isToday = !isOtherMonth && isSameDay(day.date, currentDate); diff --git a/src/datepicker/engine/flag-days.calendar.spec.ts b/src/datepicker/engine/flag-days.calendar.spec.ts new file mode 100644 index 0000000000..feb599b00e --- /dev/null +++ b/src/datepicker/engine/flag-days.calendar.spec.ts @@ -0,0 +1,42 @@ +import { flagDaysCalendar } from './flag-days-calendar'; + +describe('flag-days-calendar:', () => { + + it('should flag days as disabled when they are part of the datesDisabled', () => { + const weekViewModel = { + month: new Date('2019-02-01'), + weeks: [ + { + days: [ + { date: new Date('2019-02-07'), label: '2019-02-07' }, + { date: new Date('2019-02-08'), label: '2019-02-08' }, + { date: new Date('2019-02-09'), label: '2019-02-09' } + ]} + ], + weekNumbers: [], + weekdays: [], + monthTitle: '', + yearTitle: '' + }; + const datesDisabled = [ + new Date('2019-02-07'), + new Date('2019-02-09') + ]; + const result = flagDaysCalendar(weekViewModel, { + datesDisabled, + isDisabled: false, + minDate: new Date('2019-01-01'), + maxDate: new Date('2019-12-31'), + daysDisabled: [], + hoveredDate: new Date('2019-02-06'), + selectedDate: new Date('2019-02-05'), + selectedRange: [], + displayMonths: 1, + monthIndex: 1 + }); + + expect(result.weeks[0].days.find(day => day.label === '2019-02-07').isDisabled).toBe(true); + expect(result.weeks[0].days.find(day => day.label === '2019-02-08').isDisabled).toBe(false); + expect(result.weeks[0].days.find(day => day.label === '2019-02-09').isDisabled).toBe(true); + }); + }); diff --git a/src/datepicker/reducer/bs-datepicker.actions.ts b/src/datepicker/reducer/bs-datepicker.actions.ts index d53eb3cefb..255ccb3cc2 100644 --- a/src/datepicker/reducer/bs-datepicker.actions.ts +++ b/src/datepicker/reducer/bs-datepicker.actions.ts @@ -23,6 +23,7 @@ export class BsDatepickerActions { static readonly SET_MIN_DATE = '[datepicker] set min date'; static readonly SET_MAX_DATE = '[datepicker] set max date'; static readonly SET_DAYSDISABLED = '[datepicker] set days disabled'; + static readonly SET_DATESDISABLED = '[datepicker] set dates disabled'; static readonly SET_IS_DISABLED = '[datepicker] set is disabled'; static readonly SET_LOCALE = '[datepicker] set datepicker locale'; @@ -112,6 +113,13 @@ export class BsDatepickerActions { }; } + datesDisabled(dates: Date[]): Action { + return { + type: BsDatepickerActions.SET_DATESDISABLED, + payload: dates + }; + } + isDisabled(value: boolean): Action { return { type: BsDatepickerActions.SET_IS_DISABLED, diff --git a/src/datepicker/reducer/bs-datepicker.effects.ts b/src/datepicker/reducer/bs-datepicker.effects.ts index 4218934f67..f16d863fb8 100644 --- a/src/datepicker/reducer/bs-datepicker.effects.ts +++ b/src/datepicker/reducer/bs-datepicker.effects.ts @@ -72,6 +72,12 @@ export class BsDatepickerEffects { return this; } + setDatesDisabled(value: Date[]) { + this._store.dispatch(this._actions.datesDisabled(value)); + + return this; + } + setDisabled(value: boolean): BsDatepickerEffects { this._store.dispatch(this._actions.isDisabled(value)); diff --git a/src/datepicker/reducer/bs-datepicker.reducer.ts b/src/datepicker/reducer/bs-datepicker.reducer.ts index 6c0739becb..4a161b7290 100644 --- a/src/datepicker/reducer/bs-datepicker.reducer.ts +++ b/src/datepicker/reducer/bs-datepicker.reducer.ts @@ -287,6 +287,7 @@ function flagReducer(state: BsDatepickerState, minDate: state.minDate, maxDate: state.maxDate, daysDisabled: state.daysDisabled, + datesDisabled: state.datesDisabled, hoveredDate: state.hoveredDate, selectedDate: state.selectedDate, selectedRange: state.selectedRange, diff --git a/src/datepicker/reducer/bs-datepicker.state.ts b/src/datepicker/reducer/bs-datepicker.state.ts index f3c09e9470..70a9258990 100644 --- a/src/datepicker/reducer/bs-datepicker.state.ts +++ b/src/datepicker/reducer/bs-datepicker.state.ts @@ -31,6 +31,7 @@ export class BsDatepickerState minDate?: Date; maxDate?: Date; daysDisabled?: number[]; + datesDisabled?: Date[]; minMode?: BsDatepickerViewMode; hoveredDate?: Date; diff --git a/src/datepicker/utils/bs-calendar-utils.ts b/src/datepicker/utils/bs-calendar-utils.ts index 905c4e614f..00803e9db1 100644 --- a/src/datepicker/utils/bs-calendar-utils.ts +++ b/src/datepicker/utils/bs-calendar-utils.ts @@ -5,7 +5,8 @@ import { isBefore, shiftDate, endOf, - startOf + startOf, + isSame } from 'ngx-bootstrap/chronos'; export function getStartingDayOfCalendar(date: Date, @@ -43,3 +44,11 @@ export function isYearDisabled(date: Date, min: Date, max: Date): boolean { return minBound || maxBound; } + +export function isDisabledDate(date: Date, datesDisabled: Date[]): boolean { + if (datesDisabled === undefined || !datesDisabled || !datesDisabled.length) { + return false; + } + + return datesDisabled.some((dateDisabled: Date) => isSame(date, dateDisabled, 'date')); +}