Skip to content

Commit

Permalink
fix(datepicker): navigation restrictions work with min- and maxDate
Browse files Browse the repository at this point in the history
Fixes #1057

Closes #1077
  • Loading branch information
maxokorokov authored and pkozlowski-opensource committed Nov 24, 2016
1 parent a64a8a0 commit a12c559
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 43 deletions.
54 changes: 44 additions & 10 deletions src/datepicker/datepicker-navigation-select.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,36 +31,70 @@ describe('ngb-datepicker-navigation-select', () => {

it('should generate month options correctly', () => {
const fixture =
createTestComponent(`<ngb-datepicker-navigation-select [date]="date" [minYear]="minYear" [maxYear]="maxYear">`);
createTestComponent(`<ngb-datepicker-navigation-select [date]="date" [minDate]="minDate" [maxDate]="maxDate">`);

expect(getOptionValues(getMonthSelect(fixture.nativeElement))).toEqual([
'1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'
]);

fixture.componentInstance.minDate = new NgbDate(2016, 7, 1);
fixture.detectChanges();
expect(getOptionValues(getMonthSelect(fixture.nativeElement))).toEqual(['7', '8', '9', '10', '11', '12']);

fixture.componentInstance.maxDate = new NgbDate(2016, 9, 1);
fixture.detectChanges();
expect(getOptionValues(getMonthSelect(fixture.nativeElement))).toEqual(['7', '8', '9']);

fixture.componentInstance.minDate = new NgbDate(2015, 1, 1);
fixture.detectChanges();
expect(getOptionValues(getMonthSelect(fixture.nativeElement))).toEqual([
'1', '2', '3', '4', '5', '6', '7', '8', '9'
]);
});

it('should update months when current date changes', () => {
const fixture =
createTestComponent(`<ngb-datepicker-navigation-select [date]="date" [minDate]="minDate" [maxDate]="maxDate">`);

fixture.componentInstance.minDate = new NgbDate(2015, 7, 1);
fixture.componentInstance.maxDate = new NgbDate(2017, 7, 1);
fixture.detectChanges();
expect(getOptionValues(getMonthSelect(fixture.nativeElement))).toEqual([
'1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'
]);

fixture.componentInstance.date = new NgbDate(2015, 9, 1);
fixture.detectChanges();
expect(getOptionValues(getMonthSelect(fixture.nativeElement))).toEqual(['7', '8', '9', '10', '11', '12']);

fixture.componentInstance.date = new NgbDate(2017, 5, 1);
fixture.detectChanges();
expect(getOptionValues(getMonthSelect(fixture.nativeElement))).toEqual(['1', '2', '3', '4', '5', '6', '7']);
});

it('should generate year options correctly', () => {
const fixture =
createTestComponent(`<ngb-datepicker-navigation-select [date]="date" [minYear]="minYear" [maxYear]="maxYear">`);
createTestComponent(`<ngb-datepicker-navigation-select [date]="date" [minDate]="minDate" [maxDate]="maxDate">`);

const yearSelect = getYearSelect(fixture.nativeElement);
expect(getOptionValues(yearSelect)).toEqual(['2015', '2016', '2017', '2018', '2019', '2020']);

fixture.componentInstance.maxYear = 2017;
fixture.componentInstance.maxDate = new NgbDate(2017, 1, 1);
fixture.detectChanges();
expect(getOptionValues(yearSelect)).toEqual(['2015', '2016', '2017']);

fixture.componentInstance.minYear = 2014;
fixture.componentInstance.minDate = new NgbDate(2014, 1, 1);
fixture.detectChanges();
expect(getOptionValues(yearSelect)).toEqual(['2014', '2015', '2016', '2017']);

fixture.componentInstance.minYear = 2017;
fixture.componentInstance.minDate = new NgbDate(2017, 1, 1);
fixture.detectChanges();
expect(getOptionValues(yearSelect)).toEqual(['2017']);
});

it('should send date selection events', () => {
const fixture = createTestComponent(
`<ngb-datepicker-navigation-select [date]="date" [minYear]="minYear" [maxYear]="maxYear" (select)="onSelect($event)">`);
`<ngb-datepicker-navigation-select [date]="date" [minDate]="minDate" [maxDate]="maxDate" (select)="onSelect($event)">`);

const monthSelect = getMonthSelect(fixture.nativeElement);
const yearSelect = getYearSelect(fixture.nativeElement);
Expand All @@ -82,7 +116,7 @@ describe('ngb-datepicker-navigation-select', () => {

it('should select months and years when date changes', () => {
const fixture =
createTestComponent(`<ngb-datepicker-navigation-select [date]="date" [minYear]="minYear" [maxYear]="maxYear">`);
createTestComponent(`<ngb-datepicker-navigation-select [date]="date" [minDate]="minDate" [maxDate]="maxDate">`);

expect(getMonthSelect(fixture.nativeElement).value).toBe('8');
expect(getYearSelect(fixture.nativeElement).value).toBe('2016');
Expand All @@ -101,7 +135,7 @@ describe('ngb-datepicker-navigation-select', () => {

it('should have disabled select boxes when disabled', () => {
const fixture = createTestComponent(
`<ngb-datepicker-navigation-select [disabled]="true" [date]="date" [minYear]="minYear" [maxYear]="maxYear">`);
`<ngb-datepicker-navigation-select [disabled]="true" [date]="date" [minDate]="minDate" [maxDate]="maxDate">`);

expect(getMonthSelect(fixture.nativeElement).disabled).toBe(true);
expect(getYearSelect(fixture.nativeElement).disabled).toBe(true);
Expand All @@ -112,8 +146,8 @@ describe('ngb-datepicker-navigation-select', () => {
@Component({selector: 'test-cmp', template: ''})
class TestComponent {
date = new NgbDate(2016, 8, 22);
minYear = 2015;
maxYear = 2020;
minDate = new NgbDate(2015, 1, 1);
maxDate = new NgbDate(2020, 1, 1);

onSelect = () => {};
}
29 changes: 24 additions & 5 deletions src/datepicker/datepicker-navigation-select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,24 +32,43 @@ export class NgbDatepickerNavigationSelect implements OnChanges {

@Input() date: NgbDate;
@Input() disabled: boolean;
@Input() maxYear: number;
@Input() minYear: number;
@Input() maxDate: NgbDate;
@Input() minDate: NgbDate;

@Output() select = new EventEmitter<NgbDate>();

constructor(public i18n: NgbDatepickerI18n, calendar: NgbCalendar) { this.months = calendar.getMonths(); }
constructor(public i18n: NgbDatepickerI18n, private calendar: NgbCalendar) { this.months = calendar.getMonths(); }

ngOnChanges(changes: SimpleChanges) {
if (changes['maxYear'] || changes['minYear']) {
if (changes['maxDate'] || changes['minDate']) {
this._generateYears();
this._generateMonths();
}

if (changes['date'] && changes['date'].currentValue.year !== changes['date'].previousValue.year) {
this._generateMonths();
}
}

changeMonth(month: string) { this.select.emit(new NgbDate(this.date.year, toInteger(month), 1)); }

changeYear(year: string) { this.select.emit(new NgbDate(toInteger(year), this.date.month, 1)); }

private _generateMonths() {
this.months = this.calendar.getMonths();

if (this.date.year === this.minDate.year) {
const index = this.months.findIndex(month => month === this.minDate.month);
this.months = this.months.slice(index);
}

if (this.date.year === this.maxDate.year) {
const index = this.months.findIndex(month => month === this.maxDate.month);
this.months = this.months.slice(0, index + 1);
}
}

private _generateYears() {
this.years = Array.from({length: this.maxYear - this.minYear + 1}, (e, i) => this.minYear + i);
this.years = Array.from({length: this.maxDate.year - this.minDate.year + 1}, (e, i) => this.minDate.year + i);
}
}
49 changes: 29 additions & 20 deletions src/datepicker/datepicker-navigation.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ describe('ngb-datepicker-navigation', () => {
});

it('should toggle navigation select component', () => {
const fixture =
createTestComponent(`<ngb-datepicker-navigation [showSelect]="showSelect" [date]="date" [firstDate]="firstDate"
const fixture = createTestComponent(`<ngb-datepicker-navigation [showSelect]="showSelect" [date]="date"
[minDate]="minDate" [maxDate]="maxDate"></ngb-datepicker-navigation>`);

expect(fixture.debugElement.query(By.directive(NgbDatepickerNavigationSelect))).not.toBeNull();
Expand All @@ -44,8 +43,7 @@ describe('ngb-datepicker-navigation', () => {
});

it('should send date selection event', () => {
const fixture =
createTestComponent(`<ngb-datepicker-navigation [showSelect]="true" [date]="date" [firstDate]="firstDate"
const fixture = createTestComponent(`<ngb-datepicker-navigation [showSelect]="true" [date]="date"
[minDate]="minDate" [maxDate]="maxDate" (select)="onSelect($event)"></ngb-datepicker-navigation>`);

const monthSelect = getMonthSelect(fixture.nativeElement);
Expand All @@ -59,35 +57,49 @@ describe('ngb-datepicker-navigation', () => {
expect(fixture.componentInstance.onSelect).toHaveBeenCalledWith(new NgbDate(2020, 8, 1));
});

it('should make navigation buttons disabled', () => {
const fixture =
createTestComponent(`<ngb-datepicker-navigation [showSelect]="true" [date]="date" [firstDate]="firstDate"
it('should make prev navigation button disabled', () => {
const fixture = createTestComponent(`<ngb-datepicker-navigation [showSelect]="true" [date]="date"
[minDate]="minDate" [maxDate]="maxDate"></ngb-datepicker-navigation>`);

const links = getNavigationLinks(fixture.nativeElement);
expect(links[0].hasAttribute('disabled')).toBeFalsy();
expect(links[1].hasAttribute('disabled')).toBeFalsy();

fixture.componentInstance.minDate = new NgbDate(2016, 7, 30);
fixture.detectChanges();
expect(links[0].hasAttribute('disabled')).toBeFalsy();

fixture.componentInstance.minDate = new NgbDate(2016, 8, 1);
fixture.detectChanges();
expect(links[0].hasAttribute('disabled')).toBeTruthy();
expect(links[1].hasAttribute('disabled')).toBeFalsy();

fixture.componentInstance.firstDate = new NgbDate(2016, 9, 1);
fixture.componentInstance.date = new NgbDate(2016, 9, 1);
fixture.detectChanges();
expect(links[0].hasAttribute('disabled')).toBeFalsy();
});

it('should make next navigation button disabled', () => {
const fixture = createTestComponent(`<ngb-datepicker-navigation [showSelect]="true" [date]="date"
[minDate]="minDate" [maxDate]="maxDate"></ngb-datepicker-navigation>`);

const links = getNavigationLinks(fixture.nativeElement);
expect(links[1].hasAttribute('disabled')).toBeFalsy();

fixture.componentInstance.maxDate = new NgbDate(2016, 9, 20);
fixture.componentInstance.maxDate = new NgbDate(2016, 9, 1);
fixture.detectChanges();
expect(links[1].hasAttribute('disabled')).toBeFalsy();

fixture.componentInstance.maxDate = new NgbDate(2016, 8, 31);
fixture.detectChanges();
expect(links[0].hasAttribute('disabled')).toBeFalsy();
expect(links[1].hasAttribute('disabled')).toBeTruthy();

fixture.componentInstance.date = new NgbDate(2016, 7, 1);
fixture.detectChanges();
expect(links[1].hasAttribute('disabled')).toBeFalsy();
});

it('should have disabled navigation buttons and year and month select boxes when disabled', () => {
const fixture = createTestComponent(`<ngb-datepicker-navigation [disabled]="true" [showSelect]="true" [date]="date"
[firstDate]="firstDate" [minDate]="minDate" [maxDate]="maxDate"></ngb-datepicker-navigation>`);
const fixture = createTestComponent(`<ngb-datepicker-navigation [disabled]="true" [showSelect]="true"
[date]="date" [minDate]="minDate" [maxDate]="maxDate"></ngb-datepicker-navigation>`);

const links = getNavigationLinks(fixture.nativeElement);
expect(links[0].hasAttribute('disabled')).toBeTruthy();
Expand All @@ -97,8 +109,7 @@ describe('ngb-datepicker-navigation', () => {
});

it('should send navigation events', () => {
const fixture =
createTestComponent(`<ngb-datepicker-navigation [date]="date" [firstDate]="firstDate" [minDate]="minDate"
const fixture = createTestComponent(`<ngb-datepicker-navigation [date]="date" [minDate]="minDate"
[maxDate]="maxDate" (navigate)="onNavigate($event)"></ngb-datepicker-navigation>`);

const links = getNavigationLinks(fixture.nativeElement);
Expand All @@ -114,8 +125,7 @@ describe('ngb-datepicker-navigation', () => {
});

it('should have buttons of type button', () => {
const fixture =
createTestComponent(`<ngb-datepicker-navigation [date]="date" [firstDate]="firstDate" [minDate]="minDate"
const fixture = createTestComponent(`<ngb-datepicker-navigation [date]="date" [minDate]="minDate"
[maxDate]="maxDate"></ngb-datepicker-navigation>`);

const links = getNavigationLinks(fixture.nativeElement);
Expand All @@ -126,8 +136,7 @@ describe('ngb-datepicker-navigation', () => {

@Component({selector: 'test-cmp', template: ''})
class TestComponent {
firstDate = new NgbDate(2016, 8, 1);
date = new NgbDate(2016, 8, 22);
date = new NgbDate(2016, 8, 1);
minDate = new NgbDate(2015, 0, 1);
maxDate = new NgbDate(2020, 11, 31);
showSelect = true;
Expand Down
12 changes: 6 additions & 6 deletions src/datepicker/datepicker-navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ import {NgbCalendar} from './ngb-calendar';
<td *ngIf="showSelect">
<ngb-datepicker-navigation-select
[date]="firstDate"
[minYear]="minDate.year"
[maxYear]="maxDate.year"
[date]="date"
[minDate]="minDate"
[maxDate]="maxDate"
[disabled] = "disabled"
(select)="selectDate($event)">
</ngb-datepicker-navigation-select>
Expand All @@ -42,7 +42,6 @@ export class NgbDatepickerNavigation {

@Input() date: NgbDate;
@Input() disabled: boolean;
@Input() firstDate: NgbDate;
@Input() maxDate: NgbDate;
@Input() minDate: NgbDate;
@Input() showSelect: boolean;
Expand All @@ -56,11 +55,12 @@ export class NgbDatepickerNavigation {
doNavigate(event: NavigationEvent) { this.navigate.emit(event); }

nextDisabled() {
return this.disabled || (this.maxDate && this._calendar.getNext(this.firstDate, 'm').after(this.maxDate));
return this.disabled || (this.maxDate && this._calendar.getNext(this.date, 'm').after(this.maxDate));
}

prevDisabled() {
return this.disabled || (this.minDate && this._calendar.getPrev(this.firstDate, 'm').before(this.minDate));
const prevDate = this._calendar.getPrev(this.date, 'm');
return this.disabled || (this.minDate && prevDate.year <= this.minDate.year && prevDate.month < this.minDate.month);
}

selectDate(date: NgbDate) { this.select.emit(date); }
Expand Down
3 changes: 1 addition & 2 deletions src/datepicker/datepicker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,12 @@ export interface NgbDatepickerNavigateEvent {
</template>
<ngb-datepicker-navigation *ngIf="navigation !== 'none'"
[date]="_date"
[date]="months[0]?.firstDate"
[minDate]="_minDate"
[maxDate]="_maxDate"
[disabled]="disabled"
[showWeekNumbers]="showWeekNumbers"
[showSelect]="navigation === 'select'"
[firstDate]="months[0]?.firstDate"
(navigate)="onNavigateEvent($event)"
(select)="onNavigateDateSelect($event)">
</ngb-datepicker-navigation>
Expand Down

0 comments on commit a12c559

Please sign in to comment.