### File

`src/datepicker/datepicker.component.ts`

### Description

See demo

../../iframe.html?id=date-picker--single

### Implements

`OnDestroy` `OnChanges` `AfterViewChecked`

### Example

### Metadata

encapsulation | `ViewEncapsulation.None`
providers | `{ provide: NG_VALUE_ACCESSOR, useExisting: DatePicker, multi: true }`
selector | `ibm-date-picker`
styles | `.dayContainer { justify-content: initial; }`

template

    <div class="bx--form-item">
    	<div class="bx--form-item">
    		<div
    			class="bx--date-picker"
    			[ngClass]="{
    				'bx--date-picker--range' : range,
    				'bx--date-picker--single' : !range,
    				'bx--date-picker--light' : theme === 'light',
    				'bx--skeleton' : skeleton
    			}">
    			<div class="bx--date-picker-container">
    				<ibm-date-picker-input
    					[label]="label"
    					[placeholder]="placeholder"
    					[pattern]="pattern"
    					[id]="id"
    					[type]="(range ? 'range' : 'single')"
    					[hasIcon]="(range ? false : true)"
    					[disabled]="disabled"
    					[invalid]="invalid"
    					[invalidText]="invalidText"
    					[skeleton]="skeleton"
    					(valueChange)="onValueChange($event)">
    				</ibm-date-picker-input>
    			</div>

    			<div *ngIf="range" class="bx--date-picker-container">
    				<ibm-date-picker-input
    					[label]="rangeLabel"
    					[placeholder]="placeholder"
    					[pattern]="pattern"
    					[id]="id + '-rangeInput'"
    					[type]="(range ? 'range' : 'single')"
    					[hasIcon]="(range ? true : null)"
    					[disabled]="disabled"
    					[invalid]="invalid"
    					[invalidText]="invalidText"
    					[skeleton]="skeleton"
    					(valueChange)="onRangeValueChange($event)">
    				</ibm-date-picker-input>
    			</div>
    		</div>
    	</div>
    </div>

### Index

###### Properties

- Protected _flatpickrOptions
- Protected _value
- Private Static datePickerCount
- Protected flatpickrBaseOptions
- Protected flatpickrInstance
- onTouched
- propagateChange

###### Methods

- Protected didDateValueChange
- Protected doSelect
- Protected isFlatpickrLoaded
- ngAfterViewChecked
- ngOnChanges
- ngOnDestroy
- onRangeValueChange
- onValueChange
- registerOnChange
- registerOnTouched
- Protected setDateValues
- Protected updateClassNames
- writeValue

###### Inputs

- dateFormat
- disabled
- flatpickrOptions
- id
- invalid
- invalidText
- label
- pattern
- placeholder
- plugins
- range
- rangeLabel
- skeleton
- theme
- value

###### Outputs

- valueChange

###### HostListeners

- focusin

###### Accessors

- value
- flatpickrOptions
- flatpickrOptionsRange

### Constructor

`constructor(elementRef: ElementRef)`
Defined in src/datepicker/datepicker.component.ts:181

Parameters :

Name | Type | Optional
elementRef | `ElementRef` | No

### Inputs

`dateFormat` | Format of date For reference: https://flatpickr.js.org/formatting/ Default value : `"m/d/Y"`
Defined in src/datepicker/datepicker.component.ts:104

`disabled` | Default value : `false`
Defined in src/datepicker/datepicker.component.ts:129

`flatpickrOptions` |
Defined in src/datepicker/datepicker.component.ts:140

`id` | Default value : ``datepicker-${DatePicker.datePickerCount++}``
Defined in src/datepicker/datepicker.component.ts:114

`invalid` | Default value : `false`
Defined in src/datepicker/datepicker.component.ts:131

`invalidText` | Type : `string | TemplateRef<any>`
Defined in src/datepicker/datepicker.component.ts:133

`label` | Type : `string | TemplateRef<any>`
Defined in src/datepicker/datepicker.component.ts:106

`pattern` | Default value : `"^\\d{1,2}/\\d{1,2}/\\d{4}$"`
Defined in src/datepicker/datepicker.component.ts:112

`placeholder` | Default value : `"mm/dd/yyyy"`
Defined in src/datepicker/datepicker.component.ts:110

`plugins` | Default value : `[]`
Defined in src/datepicker/datepicker.component.ts:137

`range` | Select calendar range mode Default value : `false`
Defined in src/datepicker/datepicker.component.ts:97

`rangeLabel` | Type : `string`
Defined in src/datepicker/datepicker.component.ts:108

`skeleton` | Default value : `false`
Defined in src/datepicker/datepicker.component.ts:135

`theme` | Type : `"light" | "dark"` Default value : `"dark"`
Defined in src/datepicker/datepicker.component.ts:127

`value` | Type : `[]`
Defined in src/datepicker/datepicker.component.ts:116

### Outputs

`valueChange` | `$event` Type: `EventEmitter<any>`
Defined in src/datepicker/datepicker.component.ts:165

### HostListeners

focusin
`focusin()`
Defined in src/datepicker/datepicker.component.ts:214

### Methods

Protected didDateValueChange
`didDateValueChange(currentValue, previousValue)`
Defined in src/datepicker/datepicker.component.ts:369

Parameters :

Name | Optional
currentValue | No
previousValue | No

Returns : `boolean`

Protected doSelect
`doSelect(selectedValue: (Date | string)[])`
Defined in src/datepicker/datepicker.component.ts:364

Parameters :

Name | Type | Optional
selectedValue | `(Date | string)[]` | No

Returns : `void`

Protected isFlatpickrLoaded
`isFlatpickrLoaded()`
Defined in src/datepicker/datepicker.component.ts:376
More advanced checking of the loaded state of flatpickr Returns : `boolean`

ngAfterViewChecked
`ngAfterViewChecked()`
Defined in src/datepicker/datepicker.component.ts:200
Returns : `void`

ngOnChanges
`ngOnChanges(changes: SimpleChanges)`
Defined in src/datepicker/datepicker.component.ts:185

Parameters :

Name | Type | Optional
changes | `SimpleChanges` | No

Returns : `void`

ngOnDestroy
`ngOnDestroy()`
Defined in src/datepicker/datepicker.component.ts:242
Cleans up our flatpickr instance Returns : `void`

onRangeValueChange
`onRangeValueChange(event: string)`
Defined in src/datepicker/datepicker.component.ts:265

Handles the `valueChange` event from the range input

Parameters :

Name | Type | Optional
event | `string` | No

Returns : `void`

onValueChange
`onValueChange(event: string)`
Defined in src/datepicker/datepicker.component.ts:250

Handles the `valueChange` event from the primary/single input

Parameters :

Name | Type | Optional
event | `string` | No

Returns : `void`

registerOnChange
`registerOnChange(fn: any)`
Defined in src/datepicker/datepicker.component.ts:227

Parameters :

Name | Type | Optional
fn | `any` | No

Returns : `void`

registerOnTouched
`registerOnTouched(fn: any)`
Defined in src/datepicker/datepicker.component.ts:231

Parameters :

Name | Type | Optional
fn | `any` | No

Returns : `void`

Protected setDateValues
`setDateValues(dates: (Date | string)[])`
Defined in src/datepicker/datepicker.component.ts:326

Applies the given date value array to both the flatpickr instance and the `input`(s)

Parameters :

Name | Type | Optional | Description
dates | `(Date | string)[]` | No | `the date values to apply`

Returns : `void`

Protected updateClassNames
`updateClassNames()`
Defined in src/datepicker/datepicker.component.ts:276
Carbon uses a number of specific classnames for parts of the flatpickr - this idempotent method applies them if needed. Returns : `void`

writeValue
`writeValue(value: (Date | string)[])`
Defined in src/datepicker/datepicker.component.ts:222

Writes a value from the model to the component. Expects the value to be `null` or `(Date | string)[]`

Parameters :

Name | Type | Optional | Description
value | `(Date | string)[]` | No | `value received from the model`

Returns : `void`

### Properties

Protected _flatpickrOptions
`_flatpickrOptions: `object``
Type : `object`
Default value : `{ allowInput: true }`
Defined in src/datepicker/datepicker.component.ts:169

Protected _value
`_value: `[]``
Type : `[]`
Default value : `[]`
Defined in src/datepicker/datepicker.component.ts:167

Private Static datePickerCount
`datePickerCount: `number``
Type : `number`
Default value : `0`
Defined in src/datepicker/datepicker.component.ts:92

Protected flatpickrBaseOptions
`flatpickrBaseOptions: `object``
Type : `object`
Default value : `{ mode: "single", dateFormat: "m/d/Y", plugins: this.plugins, onOpen: () => { this.updateClassNames(); }, value: this.value }`
Defined in src/datepicker/datepicker.component.ts:173

Protected flatpickrInstance
`flatpickrInstance: `null``
Type : `null`
Default value : `null`
Defined in src/datepicker/datepicker.component.ts:181

onTouched
`onTouched: `function``
Type : `function`
Default value : `() => {}`
Defined in src/datepicker/datepicker.component.ts:235

propagateChange
`propagateChange: ```
Default value : `(_: any) => {}`
Defined in src/datepicker/datepicker.component.ts:237

### Accessors

value
get `value()`
Defined in src/datepicker/datepicker.component.ts:123
set `value(v: [])`
Defined in src/datepicker/datepicker.component.ts:116

Parameters :

Name | Type | Optional
v | `[]` | No

Returns : `void`

flatpickrOptions
get `flatpickrOptions()`
Defined in src/datepicker/datepicker.component.ts:143
set `flatpickrOptions(options)`
Defined in src/datepicker/datepicker.component.ts:140

Parameters :

Name | Optional
options | No

Returns : `void`

flatpickrOptionsRange
get `flatpickrOptionsRange()`
Defined in src/datepicker/datepicker.component.ts:160
set `flatpickrOptionsRange(options)`
Defined in src/datepicker/datepicker.component.ts:155

Parameters :

Name | Optional
options | No

Returns : `void`

    import {
    	Component,
    	Input,
    	Output,
    	EventEmitter,
    	ViewEncapsulation,
    	ElementRef,
    	OnDestroy,
    	HostListener,
    	TemplateRef,
    	OnChanges,
    	SimpleChanges,
    	AfterViewChecked
    } from "@angular/core";
    import rangePlugin from "flatpickr/dist/plugins/rangePlugin";
    import flatpickr from "flatpickr";
    import { NG_VALUE_ACCESSOR } from "@angular/forms";
    import { carbonFlatpickrMonthSelectPlugin } from "./carbon-flatpickr-month-select";

    /**
     * [See demo](../../?path=/story/date-picker--single)
     *
     * <example-url>../../iframe.html?id=date-picker--single</example-url>
     *
     * @export
     * @class DatePicker
     * @implements {OnDestroy}
     */
    @Component({
    	selector: "ibm-date-picker",
    	template: `
    	<div class="bx--form-item">
    		<div class="bx--form-item">
    			<div
    				class="bx--date-picker"
    				[ngClass]="{
    					'bx--date-picker--range' : range,
    					'bx--date-picker--single' : !range,
    					'bx--date-picker--light' : theme === 'light',
    					'bx--skeleton' : skeleton
    				}">
    				<div class="bx--date-picker-container">
    					<ibm-date-picker-input
    						[label]="label"
    						[placeholder]="placeholder"
    						[pattern]="pattern"
    						[id]="id"
    						[type]="(range ? 'range' : 'single')"
    						[hasIcon]="(range ? false : true)"
    						[disabled]="disabled"
    						[invalid]="invalid"
    						[invalidText]="invalidText"
    						[skeleton]="skeleton"
    						(valueChange)="onValueChange($event)">
    					</ibm-date-picker-input>
    				</div>

    				<div *ngIf="range" class="bx--date-picker-container">
    					<ibm-date-picker-input
    						[label]="rangeLabel"
    						[placeholder]="placeholder"
    						[pattern]="pattern"
    						[id]="id + '-rangeInput'"
    						[type]="(range ? 'range' : 'single')"
    						[hasIcon]="(range ? true : null)"
    						[disabled]="disabled"
    						[invalid]="invalid"
    						[invalidText]="invalidText"
    						[skeleton]="skeleton"
    						(valueChange)="onRangeValueChange($event)">
    					</ibm-date-picker-input>
    				</div>
    			</div>
    		</div>
    	</div>
    	`,
    	styles: [
    		`.dayContainer {
    			justify-content: initial;
    		}`
    	],
    	providers: [
    		{
    			provide: NG_VALUE_ACCESSOR,
    			useExisting: DatePicker,
    			multi: true
    		}
    	],
    	encapsulation: ViewEncapsulation.None
    })
    export class DatePicker implements OnDestroy, OnChanges, AfterViewChecked {
    	private static datePickerCount = 0;

    	/**
    	 * Select calendar range mode
    	 */
    	@Input() range = false;

    	/**
    	 * Format of date
    	 *
    	 * For reference: https://flatpickr.js.org/formatting/
    	 */
    	@Input() dateFormat = "m/d/Y";

    	@Input() label: string  | TemplateRef<any>;

    	@Input() rangeLabel: string;

    	@Input() placeholder = "mm/dd/yyyy";

    	@Input() pattern = "^\\d{1,2}/\\d{1,2}/\\d{4}$";

    	@Input() id = `datepicker-${DatePicker.datePickerCount++}`;

    	@Input() set value(v: (Date | string)[]) {
    		if (!v) {
    			v = [];
    		}
    		this._value = v;
    	}

    	get value() {
    		return this._value;
    	}

    	@Input() theme: "light" | "dark" = "dark";

    	@Input() disabled = false;

    	@Input() invalid = false;

    	@Input() invalidText: string | TemplateRef<any>;

    	@Input() skeleton = false;

    	@Input() plugins = [];

    	@Input()
    	set flatpickrOptions(options) {
    		this._flatpickrOptions = Object.assign({}, this._flatpickrOptions, options);
    	}
    	get flatpickrOptions() {
    		const plugins = [...this.plugins, carbonFlatpickrMonthSelectPlugin];
    		if (this.range) {
    			plugins.push(rangePlugin({ input: `#${this.id}-rangeInput`, position: "left"}));
    		}
    		return Object.assign({}, this._flatpickrOptions, this.flatpickrBaseOptions, {
    			mode: this.range ? "range" : "single",
    			plugins,
    			dateFormat: this.dateFormat
    		});
    	}

    	set flatpickrOptionsRange (options) {
    		console.warn("flatpickrOptionsRange is deprecated, use flatpickrOptions and set the range to true instead");
    		this.range = true;
    		this.flatpickrOptions = options;
    	}
    	get flatpickrOptionsRange () {
    		console.warn("flatpickrOptionsRange is deprecated, use flatpickrOptions and set the range to true instead");
    		return this.flatpickrOptions;
    	}

    	@Output() valueChange: EventEmitter<any> = new EventEmitter();

    	protected _value = [];

    	protected _flatpickrOptions = {
    		allowInput: true
    	};

    	protected flatpickrBaseOptions = {
    		mode: "single",
    		dateFormat: "m/d/Y",
    		plugins: this.plugins,
    		onOpen: () => { this.updateClassNames(); },
    		value: this.value
    	};

    	protected flatpickrInstance = null;

    	constructor(protected elementRef: ElementRef) { }

    	ngOnChanges(changes: SimpleChanges) {
    		if (this.isFlatpickrLoaded()) {
    			let dates = this.flatpickrInstance.selectedDates;
    			if (changes.value && this.didDateValueChange(changes.value.currentValue, changes.value.previousValue)) {
    				dates = changes.value.currentValue;
    			}
    			// only reset the flatpickr instance on Input changes
    			this.flatpickrInstance = flatpickr(`#${this.id}`, this.flatpickrOptions);
    			this.setDateValues(dates);
    		}
    	}

    	// because the actual view may be delayed in loading (think projection into a tab pane)
    	// and because we rely on a library that operates outside the Angular view of the world
    	// we need to keep trying to load the library, until the relevant DOM is actually live
    	ngAfterViewChecked() {
    		if (!this.isFlatpickrLoaded()) {
    			this.flatpickrInstance = flatpickr(`#${this.id}`, this.flatpickrOptions);

    			// if (and only if) the initialization succeeded, we can set the date values
    			if (this.isFlatpickrLoaded()) {
    				if (this.value.length > 0) {
    					this.setDateValues(this.value);
    				}
    			}
    		}
    	}

    	@HostListener("focusin")
    	onFocus() {
    		this.onTouched();
    	}

    	/**
    	 * Writes a value from the model to the component. Expects the value to be `null` or `(Date | string)[]`
    	 * @param value value received from the model
    	 */
    	writeValue(value: (Date | string)[]) {
    		this.value = value;
    		this.setDateValues(this.value);
    	}

    	registerOnChange(fn: any) {
    		this.propagateChange = fn;
    	}

    	registerOnTouched(fn: any) {
    		this.onTouched = fn;
    	}

    	onTouched: () => any = () => {};

    	propagateChange = (_: any) => {};

    	/**
    	 * Cleans up our flatpickr instance
    	 */
    	ngOnDestroy() {
    		if (!this.isFlatpickrLoaded()) { return; }
    		this.flatpickrInstance.destroy();
    	}

    	/**
    	 * Handles the `valueChange` event from the primary/single input
    	 */
    	onValueChange(event: string) {
    		if (this.isFlatpickrLoaded()) {
    			const date = this.flatpickrInstance.parseDate(event, this.dateFormat);
    			if (this.range) {
    				this.setDateValues([date, this.flatpickrInstance.selectedDates[1]]);
    			} else {
    				this.setDateValues([date]);
    			}
    			this.doSelect(this.flatpickrInstance.selectedDates);
    		}
    	}

    	/**
    	 * Handles the `valueChange` event from the range input
    	 */
    	onRangeValueChange(event: string) {
    		if (this.isFlatpickrLoaded()) {
    			const date = this.flatpickrInstance.parseDate(event, this.dateFormat);
    			this.setDateValues([this.flatpickrInstance.selectedDates[0], date]);
    			this.doSelect(this.flatpickrInstance.selectedDates);
    		}
    	}

    	/**
    	 * Carbon uses a number of specific classnames for parts of the flatpickr - this idempotent method applies them if needed.
    	 */
    	protected updateClassNames() {
    		if (!this.elementRef) { return; }

    		// get all the possible flatpickrs in the document - we need to add classes to (potentially) all of them
    		const calendarContainer = document.querySelectorAll(".flatpickr-calendar");
    		const monthContainer = document.querySelectorAll(".flatpickr-month");
    		const weekdaysContainer = document.querySelectorAll(".flatpickr-weekdays");
    		const weekdayContainer = document.querySelectorAll(".flatpickr-weekday");
    		const daysContainer = document.querySelectorAll(".flatpickr-days");
    		const dayContainer = document.querySelectorAll(".flatpickr-day");

    		// add classes to lists of elements
    		const addClassIfNotExists = (classname: string, elementList: NodeListOf<Element>) => {
    			Array.from(elementList).forEach(element => {
    				if (!element.classList.contains(classname)) {
    					element.classList.add(classname);
    				}
    			});
    		};

    		// add classes (but only if they don't exist, small perf win)
    		addClassIfNotExists("bx--date-picker__calendar", calendarContainer);
    		addClassIfNotExists("bx--date-picker__month", monthContainer);
    		addClassIfNotExists("bx--date-picker__weekdays", weekdaysContainer);
    		addClassIfNotExists("bx--date-picker__days", daysContainer);

    		// add weekday classes and format the text
    		Array.from(weekdayContainer).forEach(element => {
    			element.innerHTML = element.innerHTML.replace(/\s+/g, "");
    			element.classList.add("bx--date-picker__weekday");
    		});

    		// add day classes and special case the "today" element based on `this.value`
    		Array.from(dayContainer).forEach(element => {
    			element.classList.add("bx--date-picker__day");
    			if (!this.value) {
    				return;
    			}
    			if (element.classList.contains("today") && this.value.length > 0) {
    				element.classList.add("no-border");
    			} else if (element.classList.contains("today") && this.value.length === 0) {
    				element.classList.remove("no-border");
    			}
    		});
    	}

    	/**
    	 * Applies the given date value array to both the flatpickr instance and the `input`(s)
    	 * @param dates the date values to apply
    	 */
    	protected setDateValues(dates: (Date | string)[]) {
    		if (this.isFlatpickrLoaded()) {
    			const singleInput = this.elementRef.nativeElement.querySelector(`#${this.id}`);
    			const rangeInput = this.elementRef.nativeElement.querySelector(`#${this.id}-rangeInput`);

    			// set the date on the instance
    			this.flatpickrInstance.setDate(dates);

    			// we can either set a date value or an empty string, so we start with an empty string
    			let singleDate = "";
    			// if date is a string, parse and format
    			if (typeof dates[0] === "string") {
    				singleDate = this.flatpickrInstance.parseDate(dates[0], this.dateFormat);
    				singleDate = this.flatpickrInstance.formatDate(singleDate, this.dateFormat);
    			// if date is not a string we can assume it's a Date and we should format
    			} else if (!!dates[0]) {
    				singleDate = this.flatpickrInstance.formatDate(dates[0], this.dateFormat);
    			}
    			// apply the value
    			singleInput.value = singleDate;

    			if (rangeInput) {
    				// we can either set a date value or an empty string, so we start with an empty string
    				let rangeDate = "";
    				// if date is a string, parse and format
    				if (typeof dates[1] === "string") {
    					rangeDate = this.flatpickrInstance.parseDate(dates[1].toString(), this.dateFormat);
    					rangeDate = this.flatpickrInstance.formatDate(rangeDate, this.dateFormat);
    				// if date is not a string we can assume it's a Date and we should format
    				} else if (!!dates[1]) {
    					rangeDate = this.flatpickrInstance.formatDate(dates[1], this.dateFormat);
    				}
    				// apply the value
    				rangeInput.value = rangeDate;
    			}
    		}
    	}

    	protected doSelect(selectedValue: (Date | string)[]) {
    		this.valueChange.emit(selectedValue);
    		this.propagateChange(selectedValue);
    	}

    	protected didDateValueChange(currentValue, previousValue) {
    		return currentValue[0] !== previousValue[0] || currentValue[1] !== previousValue[1];
    	}

    	/**
    	 * More advanced checking of the loaded state of flatpickr
    	 */
    	protected isFlatpickrLoaded() {
    		// cast the instance to a boolean, and some method that has to exist for the library to be loaded in this case `setDate`
    		return !!this.flatpickrInstance && !!this.flatpickrInstance.setDate;
    	}
    }

    .dayContainer {
    			justify-content: initial;
    		}

Legend
Html element
Component
Html element with directive

# result-matching ""

# No results matching ""