Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(datepicker): start from date typed in input #1300

Merged
merged 7 commits into from
Mar 14, 2019
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import { NbCalendarCell, NbCalendarSize } from '../../model';
import { NbCalendarMonthCellComponent } from './calendar-month-cell.component';
import { NbDateService } from '../../services';

export const MONTHS_IN_VIEW = 12;
export const MONTHS_IN_COLUMN = 4;

@Component({
selector: 'nb-calendar-month-picker',
Expand Down Expand Up @@ -73,8 +75,8 @@ export class NbCalendarMonthPickerComponent<D, T> implements OnInit {
}

initMonths() {
const months: D[] = range(12).map(i => this.createMonthDateByIndex(i));
this.months = batch(months, 4);
const months: D[] = range(MONTHS_IN_VIEW).map(i => this.createMonthDateByIndex(i));
this.months = batch(months, MONTHS_IN_COLUMN);
}

onSelect(month: D) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ import { NbCalendarCell, NbCalendarSize } from '../../model';
import { NbCalendarYearCellComponent } from './calendar-year-cell.component';
import { NbDateService } from '../../services';


const defaultYearCount = 20;
export const YEARS_IN_VIEW = 20;
export const YEARS_IN_COLUMN = 4;

@Component({
selector: 'nb-calendar-year-picker',
Expand Down Expand Up @@ -83,9 +83,9 @@ export class NbCalendarYearPickerComponent<D> implements OnChanges {

initYears() {
const selectedYear = this.dateService.getYear(this.year);
const startYear = Math.ceil(selectedYear - defaultYearCount / 2);
const years = range(defaultYearCount).map(i => this.createYearDateByIndex(i + startYear));
this.years = batch(years, 4);
const startYear = Math.ceil(selectedYear - YEARS_IN_VIEW / 2);
const years = range(YEARS_IN_VIEW).map(i => this.createYearDateByIndex(i + startYear));
this.years = batch(years, YEARS_IN_COLUMN);
}

onSelect(year) {
Expand Down
12 changes: 10 additions & 2 deletions src/framework/theme/components/calendar-kit/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,16 @@

export { NbCalendarHeaderComponent } from './calendar-header/calendar-header.component';
export { NbCalendarDayCellComponent } from './calendar-day-picker/calendar-day-cell.component';
export { NbCalendarYearPickerComponent } from './calendar-year-picker/calendar-year-picker.component';
export { NbCalendarMonthPickerComponent } from './calendar-month-picker/calendar-month-picker.component';
export {
NbCalendarYearPickerComponent,
YEARS_IN_VIEW,
YEARS_IN_COLUMN,
} from './calendar-year-picker/calendar-year-picker.component';
export {
NbCalendarMonthPickerComponent,
MONTHS_IN_VIEW,
MONTHS_IN_COLUMN,
yggg marked this conversation as resolved.
Show resolved Hide resolved
} from './calendar-month-picker/calendar-month-picker.component';
export { NbCalendarDayPickerComponent } from './calendar-day-picker/calendar-day-picker.component';
export { NbCalendarNavigationComponent } from './calendar-navigation/calendar-navigation.component';
export { NbCalendarPageableNavigationComponent } from './calendar-navigation/calendar-pageable-navigation.component';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@

import { Component, EventEmitter, HostBinding, Input, OnInit, Output, Type } from '@angular/core';

import { NbDateService, NbCalendarCell, NbCalendarSize, NbCalendarViewMode } from '../calendar-kit';

import { NbDateService, NbCalendarCell, NbCalendarSize, NbCalendarViewMode, YEARS_IN_VIEW } from '../calendar-kit';

/**
* The basis for calendar and range calendar components.
Expand Down Expand Up @@ -139,6 +138,6 @@ export class NbBaseCalendarComponent<D, T> implements OnInit {
}

private changeVisibleYear(direction: number) {
this.visibleDate = this.dateService.addYear(this.visibleDate, direction * 20);
this.visibleDate = this.dateService.addYear(this.visibleDate, direction * YEARS_IN_VIEW);
}
}
17 changes: 14 additions & 3 deletions src/framework/theme/components/datepicker/datepicker.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ export class NbDatepickerComponent<D> extends NbBasePicker<D, D, NbCalendarCompo
}

if (date) {
this.visibleDate = date;
this.picker.visibleDate = date;
this.picker.date = date;
}
Expand All @@ -409,7 +410,11 @@ export class NbDatepickerComponent<D> extends NbBasePicker<D, D, NbCalendarCompo
}

protected writeQueue() {
this.value = this.queue;
if (this.queue) {
const date = this.queue;
this.queue = null;
this.value = date;
}
}
}

Expand Down Expand Up @@ -449,7 +454,9 @@ export class NbRangepickerComponent<D> extends NbBasePicker<D, NbCalendarRange<D
}

if (range) {
this.picker.visibleDate = range && range.start;
const visibleDate = range && range.start;
this.visibleDate = visibleDate;
this.picker.visibleDate = visibleDate;
this.picker.range = range;
}
}
Expand All @@ -463,6 +470,10 @@ export class NbRangepickerComponent<D> extends NbBasePicker<D, NbCalendarRange<D
}

protected writeQueue() {
this.value = this.queue;
if (this.queue) {
const range = this.queue;
this.queue = null;
this.value = range;
yggg marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
214 changes: 209 additions & 5 deletions src/framework/theme/components/datepicker/datepicker.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
import { ApplicationRef, Component, ViewChild } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { NbDatepickerDirective } from '@nebular/theme';
import { skip } from 'rxjs/operators';
import { NbCalendarRange, NbDatepickerDirective } from '@nebular/theme';

import { NbDatepickerModule } from './datepicker.module';
import { NbThemeModule } from '../../theme.module';
import { NbLayoutModule } from '../layout/layout.module';
import { NbDatepickerComponent } from './datepicker.component';

import { NbDatepickerComponent, NbRangepickerComponent } from './datepicker.component';

@Component({
selector: 'nb-datepicker-test',
Expand All @@ -31,6 +31,22 @@ export class NbDatepickerTestComponent {
@ViewChild(NbDatepickerDirective) datepickerDirective: NbDatepickerDirective<Date>;
}

@Component({
selector: 'nb-rangepicker-test',
template: `
<nb-layout>
<nb-layout-column>
<input [nbDatepicker]="rangepicker">
<nb-rangepicker #rangepicker></nb-rangepicker>
</nb-layout-column>
</nb-layout>
`,
})
export class NbRangepickerTestComponent {
@ViewChild(NbRangepickerComponent) rangepicker: NbRangepickerComponent<Date>;
@ViewChild(NbDatepickerDirective) datepickerDirective: NbDatepickerDirective<Date>;
}

describe('nb-datepicker', () => {
let fixture: ComponentFixture<NbDatepickerTestComponent>;
let appRef: ApplicationRef;
Expand Down Expand Up @@ -101,8 +117,7 @@ describe('nb-datepicker', () => {
cell.dispatchEvent(new Event('click'));
});

it('should select date typed in to the input', () => {
datepicker.visibleDate = new Date(2018, 8, 17);
it('should start from date typed into the input', () => {
input.value = 'Sep 17, 2018';
input.dispatchEvent(new Event('input'));
showDatepicker();
Expand All @@ -113,6 +128,37 @@ describe('nb-datepicker', () => {
expect(cell.textContent).toContain('17');
});

it('should start from current date if input is empty', () => {
showDatepicker();
appRef.tick();
expect(overlay.querySelector('.day-cell.today')).toBeDefined();
});

it('should start from current date if input value is invalid', () => {
input.value = 'definitely not a date';
input.dispatchEvent(new Event('input'));
showDatepicker();
appRef.tick();
expect(overlay.querySelector('.day-cell.today')).toBeDefined();
});

it('should update visible date if input value changed', () => {
const initialDate = new Date(2000, 0, 1);
datepicker.visibleDate = initialDate;

const date = 17;
const month = 8;
const year = 2018;
input.value = 'Sep 17, 2018';
input.dispatchEvent(new Event('input'));
showDatepicker();
appRef.tick();

expect(datepicker.visibleDate.getDate()).toEqual(date);
expect(datepicker.visibleDate.getMonth()).toEqual(month);
expect(datepicker.visibleDate.getFullYear()).toEqual(year);
});

it('should be valid if empty', () => {
expect(datepickerDirective.validate()).toBe(null);
});
Expand All @@ -125,3 +171,161 @@ describe('nb-datepicker', () => {
expect(datepickerDirective.validate()).not.toBe(null);
});
});

describe('nb-rangepicker', () => {
let fixture: ComponentFixture<NbRangepickerTestComponent>;
let appRef: ApplicationRef;
let rangepicker: NbRangepickerComponent<Date>;
let datepickerDirective: NbDatepickerDirective<Date>;
let overlay: HTMLElement;
let input: HTMLInputElement;

const showRangepicker = () => {
rangepicker.show();
appRef.tick();
};

beforeEach(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule.withRoutes([]),
NbThemeModule.forRoot(),
NbLayoutModule,
NbDatepickerModule.forRoot(),
],
declarations: [NbRangepickerTestComponent],
});

fixture = TestBed.createComponent(NbRangepickerTestComponent);
appRef = TestBed.get(ApplicationRef);

fixture.detectChanges();
});

beforeEach(() => {
rangepicker = fixture.componentInstance.rangepicker;
datepickerDirective = fixture.componentInstance.datepickerDirective;
overlay = fixture.nativeElement.querySelector('nb-layout');
input = fixture.nativeElement.querySelector('input');
});

it('should render calendar', () => {
showRangepicker();
const calendar = overlay.querySelector('nb-calendar-range');
expect(calendar).toBeTruthy();
});

it('should not render overlay on load', () => {
const datepickerContainer = overlay.querySelector('nb-datepicker-container');
expect(datepickerContainer).toBeNull();
});

it('should render overlay lazily', () => {
const datepickerContainer = overlay.querySelector('nb-datepicker-container');
expect(datepickerContainer).toBeNull();
showRangepicker();
const calendar = overlay.querySelector('nb-calendar-range');
expect(calendar).toBeTruthy();
});

it('should emit rangeChange when selected start date', (done) => {
rangepicker.visibleDate = new Date(2018, 8, 17);
showRangepicker();

rangepicker.rangeChange.subscribe((range: NbCalendarRange<Date>) => {
expect(range.start.getFullYear()).toEqual(2018);
expect(range.start.getMonth()).toEqual(8);
expect(range.start.getDate()).toEqual(1);
expect(range.end).not.toBeDefined();
done();
});

// click on Sep 1
const startCell = overlay.querySelectorAll('.day-cell')[6];
(startCell as HTMLElement).click();

fixture.detectChanges();
}, 5000);

it('should emit rangeChange when selected start and end dates', (done) => {
rangepicker.visibleDate = new Date(2018, 8, 17);
showRangepicker();

rangepicker.rangeChange
.pipe(skip(1))
.subscribe((range: NbCalendarRange<Date>) => {
expect(range.start.getFullYear()).toEqual(2018);
expect(range.end.getFullYear()).toEqual(2018);
expect(range.start.getMonth()).toEqual(8);
expect(range.end.getMonth()).toEqual(8);
expect(range.start.getDate()).toEqual(1);
expect(range.end.getDate()).toEqual(3);
done();
});

// click on Sep 1
const startCell = overlay.querySelectorAll('.day-cell')[6];
(startCell as HTMLElement).click();
// click on Sep 3
const endCell = overlay.querySelectorAll('.day-cell')[8];
(endCell as HTMLElement).click();

fixture.detectChanges();
}, 5000);

it('should start from date typed into the input', () => {
input.value = 'Sep 17, 2018 - Sep 19, 2018';
input.dispatchEvent(new Event('input'));
showRangepicker();
appRef.tick();

const startCell = overlay.querySelector('.day-cell.in-range.start');
const endCell = overlay.querySelector('.day-cell.in-range.end');

expect(startCell.textContent).toContain('17');
expect(endCell.textContent).toContain('19');
});

it('should start from current date if input is empty', () => {
showRangepicker();
appRef.tick();
expect(overlay.querySelector('.day-cell.today')).toBeDefined();
});

it('should start from current date if input value is invalid', () => {
input.value = 'definitely not a date';
input.dispatchEvent(new Event('input'));
showRangepicker();
appRef.tick();
expect(overlay.querySelector('.day-cell.today')).toBeDefined();
});

it('should set visible date to start date if input value changed', () => {
const initialDate = new Date(2000, 0, 1);
rangepicker.visibleDate = initialDate;

const date = 17;
const month = 8;
const year = 2018;
input.value = 'Sep 17, 2018 - Sep 19, 2018';
input.dispatchEvent(new Event('input'));
appRef.tick();
showRangepicker();

expect(rangepicker.visibleDate.getDate()).toEqual(date);
expect(rangepicker.visibleDate.getMonth()).toEqual(month);
expect(rangepicker.visibleDate.getFullYear()).toEqual(year);
});

it('should be valid if empty', () => {
expect(datepickerDirective.validate()).toBe(null);
});

it('should not be valid if empty contain incorrectly formatted date', () => {
input.value = 'somecurruptedinput';
input.dispatchEvent(new Event('input'));
showRangepicker();

expect(datepickerDirective.validate()).not.toBe(null);
});
});