Skip to content

Commit

Permalink
fix(datepicker): focus correct day when opening popup
Browse files Browse the repository at this point in the history
Algorithm:
If a date is selected -> focus date
If startDate: {year, month, day} is specified -> focus startDate
If startDate: {year, month} is specified -> focus 1st day of startDate
If today is visible -> focus today
Otherwise focus first date of visible month

Fixes #2136

Closes #2796
  • Loading branch information
maxokorokov authored and pkozlowski-opensource committed Oct 26, 2018
1 parent dac43f4 commit 838693a
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 15 deletions.
25 changes: 20 additions & 5 deletions e2e-app/e2e/src/datepicker/datepicker-focus.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,22 @@ describe('Datepicker', () => {
await expectFocused(page.getToday(), `Today's date should be focused`);
});

it(`should focus 1st day of month when opened with pre-selected date`, async() => {
it(`should focus selected day when opened`, async() => {
await page.preSelectDate(); // 10 AUG 2018
await page.openDatepicker();
await expectFocused(page.getDayElement(new Date(2018, 7, 1)), `First date of month should be focused`);
await expectFocused(page.getDayElement(new Date(2018, 7, 10)), `Selected date should be focused`);
});

it(`should focus 1st day of {year, month} startDate day when opened`, async() => {
await page.selectStartDate('month-only'); // startDate = AUG 2018
await page.openDatepicker();
await expectFocused(page.getDayElement(new Date(2018, 7, 1)), `First day of startDate should be focused`);
});

it(`should focus {year, month, day} startDate day when opened`, async() => {
await page.selectStartDate('month-and-day'); // startDate = 10 AUG 2018
await page.openDatepicker();
await expectFocused(page.getDayElement(new Date(2018, 7, 10)), `First day of startDate should be focused`);
});

it(`should be closed on toggle element click and focus it`, async() => {
Expand Down Expand Up @@ -182,13 +194,16 @@ describe('Datepicker', () => {
await page.preSelectDate(); // 10 AUG 2018
await page.openDatepicker();

await expectFocused(page.getDayElement(new Date(2018, 7, 1)), `01 AUG should be focused`);
await expectFocused(page.getDayElement(new Date(2018, 7, 10)), `10 AUG should be focused`);

await sendKey(Key.ARROW_UP);
await expectFocused(page.getDayElement(new Date(2018, 7, 3)), `03 AUG should be focused`);

await sendKey(Key.ARROW_UP);
await expectFocused(page.getDayElement(new Date(2018, 6, 25)), `25 JUL should be focused`);
await expectFocused(page.getDayElement(new Date(2018, 6, 27)), `27 JUL should be focused`);

await sendKey(Key.ARROW_DOWN);
await expectFocused(page.getDayElement(new Date(2018, 7, 1)), `01 AUG should be focused`);
await expectFocused(page.getDayElement(new Date(2018, 7, 3)), `03 AUG should be focused`);
});

it(`should focus previous day with 'ArrowLeft'`, async() => {
Expand Down
5 changes: 5 additions & 0 deletions e2e-app/e2e/src/datepicker/datepicker-focus.po.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,9 @@ import {DatepickerPage} from './datepicker.po';

export class DatepickerFocusPage extends DatepickerPage {
async preSelectDate() { await $('#selectDate').click(); }

async selectStartDate(type: string) {
await $('#start-date-dropdown').click();
await $(`#start-date-${type}`).click();
}
}
25 changes: 20 additions & 5 deletions e2e-app/src/app/datepicker/focus/datepicker-focus.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,29 @@ <h3>Datepicker focus tests</h3>
<form>
<div class="form-group form-inline">
<div class="input-group">
<input class="form-control" name="dp" placeholder="yyyy-mm-dd"
#d="ngbDatepicker" ngbDatepicker [(ngModel)]="model"
[minDate]="{year: 2000, month: 1, day: 1}" [maxDate]="{year: 2100, month: 1, day: 1}">
<input class="form-control" name="dp" placeholder="yyyy-mm-dd" #d="ngbDatepicker" ngbDatepicker [(ngModel)]="model"
[minDate]="{year: 2000, month: 1, day: 1}" [maxDate]="{year: 2100, month: 1, day: 1}" [startDate]="startDate">
<div class="input-group-append">
<button class="btn btn-outline-secondary" type="button" id="toggle" (click)="d.toggle()">Toggle</button>
<button class="btn btn-outline-secondary" type="button" id="selectDate" (click)="model = {year: 2018, month: 8, day: 10}">10 AUG 2018</button>
<button class="btn btn-outline-secondary" type="button" id="selectDate" (click)="model = {year: 2018, month: 8, day: 10}">10
AUG 2018</button>
</div>
</div>

<div ngbDropdown class="d-inline-block ml-3">
<button class="btn btn-outline-secondary" id="start-date-dropdown" ngbDropdownToggle>Choose Start date</button>
<div ngbDropdownMenu aria-labelledby="dropdownBasic1">
<button class="dropdown-item" id="start-date-null" (click)="startDate = null">Null</button>
<button class="dropdown-item" id="start-date-month-only" (click)="startDate = {year: 2018, month: 8}">AUG 2018</button>
<button class="dropdown-item" id="start-date-month-and-day" (click)="startDate = {year: 2018, month: 8, day: 10}">10
AUG 2018</button>
</div>
</div>

<span class="ml-3">startDate is
<span id="start-date">{{ startDate | json }}</span>
</span>

</div>
</form>

</form>
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ import {Component} from '@angular/core';
@Component({templateUrl: './datepicker-focus.component.html'})
export class DatepickerFocusComponent {
model = null;
startDate = null;
}
4 changes: 2 additions & 2 deletions src/datepicker/datepicker-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ export class NgbInputDatepicker implements OnChanges,
* If nothing or invalid date provided, calendar will open with current month.
* Use 'navigateTo(date)' as an alternative
*/
@Input() startDate: {year: number, month: number};
@Input() startDate: {year: number, month: number, day?: number};

/**
* A selector specifying the element the datepicker popup should be appended to.
Expand Down Expand Up @@ -354,7 +354,7 @@ export class NgbInputDatepicker implements OnChanges,
* If nothing or invalid date provided calendar will open current month.
* Use 'startDate' input as an alternative
*/
navigateTo(date?: {year: number, month: number}) {
navigateTo(date?: {year: number, month: number, day?: number}) {
if (this.isOpen()) {
this._cRef.instance.navigateTo(date);
}
Expand Down
6 changes: 3 additions & 3 deletions src/datepicker/datepicker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ export class NgbDatepicker implements OnDestroy,
* If nothing or invalid date provided, calendar will open with current month.
* Use 'navigateTo(date)' as an alternative
*/
@Input() startDate: {year: number, month: number};
@Input() startDate: {year: number, month: number, day?: number};

/**
* An event fired when navigation happens and currently displayed month changes.
Expand Down Expand Up @@ -265,8 +265,8 @@ export class NgbDatepicker implements OnDestroy,
* If nothing or invalid date provided calendar will open current month.
* Use 'startDate' input as an alternative
*/
navigateTo(date?: {year: number, month: number}) {
this._service.open(NgbDate.from(date ? {...date, day: 1} : null));
navigateTo(date?: {year: number, month: number, day?: number}) {
this._service.open(NgbDate.from(date ? date.day ? date as NgbDateStruct : {...date, day: 1} : null));
}

ngOnDestroy() {
Expand Down

0 comments on commit 838693a

Please sign in to comment.