From a9ce83ed00d7b9d0e64dc120e29a7839213b5d19 Mon Sep 17 00:00:00 2001 From: IAfanasov Date: Sun, 7 Jul 2019 10:06:43 +0200 Subject: [PATCH] feat(datepicker): input datepicker global config Closes #3273 --- .../demos/config/datepicker-config.html | 14 ++++- .../demos/config/datepicker-config.ts | 25 ++++++--- .../datepicker-input-config.spec.ts | 12 +++++ src/datepicker/datepicker-input-config.ts | 17 ++++++ src/datepicker/datepicker-input.spec.ts | 53 +++++++++++++++++++ src/datepicker/datepicker-input.ts | 8 +-- src/datepicker/datepicker.module.ts | 1 + src/index.ts | 1 + 8 files changed, 120 insertions(+), 11 deletions(-) create mode 100644 src/datepicker/datepicker-input-config.spec.ts create mode 100644 src/datepicker/datepicker-input-config.ts diff --git a/demo/src/app/components/datepicker/demos/config/datepicker-config.html b/demo/src/app/components/datepicker/demos/config/datepicker-config.html index 83d2f3064e..7c550c3532 100644 --- a/demo/src/app/components/datepicker/demos/config/datepicker-config.html +++ b/demo/src/app/components/datepicker/demos/config/datepicker-config.html @@ -1,3 +1,13 @@ -

This datepicker uses customized default values.

+

This datepicker input uses customized default values.

- +
+
+
+ +
+ +
+
+
+
diff --git a/demo/src/app/components/datepicker/demos/config/datepicker-config.ts b/demo/src/app/components/datepicker/demos/config/datepicker-config.ts index d03851b3ea..d3e71225ee 100644 --- a/demo/src/app/components/datepicker/demos/config/datepicker-config.ts +++ b/demo/src/app/components/datepicker/demos/config/datepicker-config.ts @@ -1,5 +1,11 @@ import {Component} from '@angular/core'; -import {NgbDatepickerConfig, NgbCalendar, NgbDate, NgbDateStruct} from '@ng-bootstrap/ng-bootstrap'; +import { + NgbDatepickerConfig, + NgbCalendar, + NgbDate, + NgbDateStruct, + NgbInputDatepickerConfig +} from '@ng-bootstrap/ng-bootstrap'; @Component({ selector: 'ngbd-datepicker-config', @@ -10,15 +16,22 @@ export class NgbdDatepickerConfig { model: NgbDateStruct; - constructor(config: NgbDatepickerConfig, calendar: NgbCalendar) { + constructor( + datepickerConfig: NgbDatepickerConfig, inputDatepickerConfig: NgbInputDatepickerConfig, calendar: NgbCalendar) { // customize default values of datepickers used by this component tree - config.minDate = {year: 1900, month: 1, day: 1}; - config.maxDate = {year: 2099, month: 12, day: 31}; + datepickerConfig.minDate = {year: 1900, month: 1, day: 1}; + datepickerConfig.maxDate = {year: 2099, month: 12, day: 31}; // days that don't belong to current month are not visible - config.outsideDays = 'hidden'; + datepickerConfig.outsideDays = 'hidden'; // weekends are disabled - config.markDisabled = (date: NgbDate) => calendar.getWeekday(date) >= 6; + datepickerConfig.markDisabled = (date: NgbDate) => calendar.getWeekday(date) >= 6; + + // setting datepicker popup to close only on click outside + inputDatepickerConfig.autoClose = 'outside'; + + // setting datepicker popup to open above the input + inputDatepickerConfig.placement = ['top-left', 'top-right']; } } diff --git a/src/datepicker/datepicker-input-config.spec.ts b/src/datepicker/datepicker-input-config.spec.ts new file mode 100644 index 0000000000..7df4346ada --- /dev/null +++ b/src/datepicker/datepicker-input-config.spec.ts @@ -0,0 +1,12 @@ +import {NgbInputDatepickerConfig} from './datepicker-input-config'; + +describe('NgbInputDatepickerConfig', () => { + it('should have sensible default values', () => { + const config = new NgbInputDatepickerConfig(); + + expect(config.autoClose).toBe(true); + expect(config.container).toBeUndefined(); + expect(config.positionTarget).toBeUndefined(); + expect(config.placement).toEqual(['bottom-left', 'bottom-right', 'top-left', 'top-right']); + }); +}); diff --git a/src/datepicker/datepicker-input-config.ts b/src/datepicker/datepicker-input-config.ts new file mode 100644 index 0000000000..4366b7389e --- /dev/null +++ b/src/datepicker/datepicker-input-config.ts @@ -0,0 +1,17 @@ +import {Injectable} from '@angular/core'; + +import {PlacementArray} from '../util/positioning'; + +/** + * A configuration service for the [`NgbDatepickerInput`](#/components/datepicker/api#NgbDatepicker) component. + * + * You can inject this service, typically in your root component, and customize the values of its properties in + * order to provide default values for all the datepicker inputs used in the application. + */ +@Injectable({providedIn: 'root'}) +export class NgbInputDatepickerConfig { + autoClose: boolean | 'inside' | 'outside' = true; + container: null | 'body'; + positionTarget: string | HTMLElement; + placement: PlacementArray = ['bottom-left', 'bottom-right', 'top-left', 'top-right']; +} diff --git a/src/datepicker/datepicker-input.spec.ts b/src/datepicker/datepicker-input.spec.ts index 910bd1d55f..437b87986c 100644 --- a/src/datepicker/datepicker-input.spec.ts +++ b/src/datepicker/datepicker-input.spec.ts @@ -11,6 +11,7 @@ import {NgbDatepicker} from './datepicker'; import {NgbDateStruct} from './ngb-date-struct'; import {NgbDate} from './ngb-date'; import * as positioning from 'src/util/positioning'; +import {NgbInputDatepickerConfig} from './datepicker-input-config'; const createTestCmpt = (html: string) => createGenericTestComponent(html, TestComponent) as ComponentFixture; @@ -18,12 +19,64 @@ const createTestCmpt = (html: string) => const createTestNativeCmpt = (html: string) => createGenericTestComponent(html, TestNativeComponent) as ComponentFixture; +function expectSameValues(inputDatepicker: NgbInputDatepicker, config: NgbInputDatepickerConfig) { + ['autoClose', 'container', 'positionTarget', 'placement'].forEach( + field => expect(inputDatepicker[field]).toEqual(config[field], field)); +} + +function customizeConfig(config: NgbInputDatepickerConfig) { + config.autoClose = 'outside'; + config.container = 'body'; + config.positionTarget = 'positionTarget'; + config.placement = ['bottom-left', 'top-right']; +} + describe('NgbInputDatepicker', () => { beforeEach(() => { TestBed.configureTestingModule({declarations: [TestComponent], imports: [NgbDatepickerModule, FormsModule]}); }); + it('should initialize inputs with provided datepicker config', () => { + const defaultConfig = new NgbInputDatepickerConfig(); + const fixture = createTestCmpt(``); + + const inputDatepicker = + fixture.debugElement.query(By.directive(NgbInputDatepicker)).injector.get(NgbInputDatepicker); + expectSameValues(inputDatepicker, defaultConfig); + }); + + it('should initialize inputs with provided config', () => { + // overrideComponent should happen before any injections, so createTestCmpt will fail here + TestBed.overrideComponent(TestComponent, {set: {template: ''}}); + const config = TestBed.get(NgbInputDatepickerConfig); + customizeConfig(config); + const fixture = TestBed.createComponent(TestComponent); + fixture.detectChanges(); + + const inputDatepicker = + fixture.debugElement.query(By.directive(NgbInputDatepicker)).injector.get(NgbInputDatepicker); + expectSameValues(inputDatepicker, config); + }); + + describe('Custom config as provider', () => { + const config = new NgbInputDatepickerConfig(); + customizeConfig(config); + + beforeEach(() => { + TestBed.configureTestingModule( + {imports: [NgbDatepickerModule], providers: [{provide: NgbInputDatepickerConfig, useValue: config}]}); + }); + + it('should initialize inputs with provided config as provider', () => { + const fixture = createTestCmpt(``); + + const inputDatepicker = + fixture.debugElement.query(By.directive(NgbInputDatepicker)).injector.get(NgbInputDatepicker); + expectSameValues(inputDatepicker, config); + }); + }); + describe('open, close and toggle', () => { it('should allow controlling datepicker popup from outside', () => { diff --git a/src/datepicker/datepicker-input.ts b/src/datepicker/datepicker-input.ts index 2cabfdabce..be9366e618 100644 --- a/src/datepicker/datepicker-input.ts +++ b/src/datepicker/datepicker-input.ts @@ -32,6 +32,7 @@ import {NgbCalendar} from './ngb-calendar'; import {NgbDate} from './ngb-date'; import {NgbDateParserFormatter} from './ngb-date-parser-formatter'; import {NgbDateStruct} from './ngb-date-struct'; +import {NgbInputDatepickerConfig} from './datepicker-input-config'; const NGB_DATEPICKER_VALUE_ACCESSOR = { provide: NG_VALUE_ACCESSOR, @@ -81,7 +82,7 @@ export class NgbInputDatepicker implements OnChanges, * * @since 3.0.0 */ - @Input() autoClose: boolean | 'inside' | 'outside' = true; + @Input() autoClose: boolean | 'inside' | 'outside'; /** * The reference to a custom template for the day. @@ -177,7 +178,7 @@ export class NgbInputDatepicker implements OnChanges, * * Please see the [positioning overview](#/positioning) for more details. */ - @Input() placement: PlacementArray = ['bottom-left', 'bottom-right', 'top-left', 'top-right']; + @Input() placement: PlacementArray; /** * If `true`, weekdays will be displayed. @@ -260,7 +261,8 @@ export class NgbInputDatepicker implements OnChanges, private _vcRef: ViewContainerRef, private _renderer: Renderer2, private _cfr: ComponentFactoryResolver, private _ngZone: NgZone, private _service: NgbDatepickerService, private _calendar: NgbCalendar, private _dateAdapter: NgbDateAdapter, @Inject(DOCUMENT) private _document: any, - private _changeDetector: ChangeDetectorRef) { + private _changeDetector: ChangeDetectorRef, config: NgbInputDatepickerConfig) { + ['autoClose', 'container', 'positionTarget', 'placement'].forEach(input => this[input] = config[input]); this._zoneSubscription = _ngZone.onStable.subscribe(() => this._updatePopupPosition()); } diff --git a/src/datepicker/datepicker.module.ts b/src/datepicker/datepicker.module.ts index 850f9ee9b3..8feb350a8c 100644 --- a/src/datepicker/datepicker.module.ts +++ b/src/datepicker/datepicker.module.ts @@ -21,6 +21,7 @@ export {NgbDatepickerDayView} from './datepicker-day-view'; export {NgbDatepickerNavigation} from './datepicker-navigation'; export {NgbDatepickerNavigationSelect} from './datepicker-navigation-select'; export {NgbDatepickerConfig} from './datepicker-config'; +export {NgbInputDatepickerConfig} from './datepicker-input-config'; export {NgbDatepickerI18n} from './datepicker-i18n'; export {NgbDateStruct} from './ngb-date-struct'; export {NgbDate} from './ngb-date'; diff --git a/src/index.ts b/src/index.ts index ddc59a1f97..af0d0c98af 100644 --- a/src/index.ts +++ b/src/index.ts @@ -58,6 +58,7 @@ export { NgbDateParserFormatter, NgbDatepicker, NgbDatepickerConfig, + NgbInputDatepickerConfig, NgbDatepickerI18n, NgbDatepickerI18nHebrew, NgbDatepickerKeyboardService,