Skip to content

Commit

Permalink
feat(datepicker): wire up selected value propagation (#3330)
Browse files Browse the repository at this point in the history
* enable value propagation through various components & directives

* add tests

* fix lint

* addressed comments

* addressed feedback

* fix lint

* make datepicker selected property internal

* add test for pristine after ngModel change
  • Loading branch information
mmalerba committed Apr 20, 2017
1 parent 2cedeae commit 24dcc15
Show file tree
Hide file tree
Showing 11 changed files with 421 additions and 55 deletions.
7 changes: 1 addition & 6 deletions src/demo-app/datepicker/datepicker-demo.html
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
<h1>Work in progress, not ready for use.</h1>

<md-calendar [startAt]="startAt" [(selected)]="selected"></md-calendar>

<br>
<div>{{selected?.toNativeDate()}}</div>

<input [mdDatepicker]="dp">
<input [mdDatepicker]="dp" [(ngModel)]="date">
<button (click)="dp.openStandardUi()">open</button>
<button (click)="dp.openTouchUi()">open (mobile)</button>
<md-datepicker #dp></md-datepicker>
4 changes: 1 addition & 3 deletions src/demo-app/datepicker/datepicker-demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,5 @@ import {SimpleDate} from '@angular/material';
styleUrls: ['datepicker-demo.css'],
})
export class DatepickerDemo {
startAt = new SimpleDate(2017, 0, 1);
date = SimpleDate.today();
selected: SimpleDate;
date: SimpleDate;
}
9 changes: 5 additions & 4 deletions src/lib/datepicker/calendar-table.spec.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import {async, TestBed, ComponentFixture} from '@angular/core/testing';
import {MdDatepickerModule} from './index';
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import {Component} from '@angular/core';
import {MdCalendarTable, MdCalendarCell} from './calendar-table';
import {MdCalendarCell, MdCalendarTable} from './calendar-table';
import {By} from '@angular/platform-browser';


describe('MdCalendarTable', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [MdDatepickerModule],
declarations: [
MdCalendarTable,

// Test components.
StandardCalendarTable,
],
});
Expand Down
17 changes: 14 additions & 3 deletions src/lib/datepicker/calendar.spec.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,27 @@
import {async, TestBed, ComponentFixture} from '@angular/core/testing';
import {MdDatepickerModule} from './index';
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import {Component} from '@angular/core';
import {SimpleDate} from '../core/datetime/simple-date';
import {MdCalendar} from './calendar';
import {By} from '@angular/platform-browser';
import {MdMonthView} from './month-view';
import {MdYearView} from './year-view';
import {MdCalendarTable} from './calendar-table';
import {DatetimeModule} from '../core/datetime/index';


describe('MdCalendar', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [MdDatepickerModule],
imports: [
DatetimeModule,
],
declarations: [
MdCalendar,
MdCalendarTable,
MdMonthView,
MdYearView,

// Test components.
StandardCalendar,
],
});
Expand Down
85 changes: 81 additions & 4 deletions src/lib/datepicker/datepicker-input.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,100 @@
import {Directive, ElementRef, Input} from '@angular/core';
import {
AfterContentInit, Directive, ElementRef, forwardRef, Input, OnDestroy,
Renderer
} from '@angular/core';
import {MdDatepicker} from './datepicker';
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
import {SimpleDate} from '../core/datetime/simple-date';
import {CalendarLocale} from '../core/datetime/calendar-locale';
import {Subscription} from 'rxjs';


export const MD_DATEPICKER_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => MdDatepickerInput),
multi: true
};


/** Directive used to connect an input to a MdDatepicker. */
@Directive({
selector: 'input[mdDatepicker], input[matDatepicker]',
providers: [MD_DATEPICKER_VALUE_ACCESSOR],
host: {
'(input)': '_onChange($event.target.value)',
'(blur)': '_onTouched()',
}
})
export class MdDatepickerInput {
export class MdDatepickerInput implements AfterContentInit, ControlValueAccessor, OnDestroy {
@Input()
set mdDatepicker(value: MdDatepicker) {
if (value) {
this._datepicker = value;
this._datepicker._registerInput(this._elementRef);
this._datepicker._registerInput(this);
}
}
private _datepicker: MdDatepicker;

@Input()
get value(): SimpleDate {
return this._value;
}
set value(value: SimpleDate) {
this._value = this._locale.parseDate(value);
const stringValue = this._value == null ? '' : this._locale.formatDate(this._value);
this._renderer.setElementProperty(this._elementRef.nativeElement, 'value', stringValue);
}
private _value: SimpleDate;

@Input()
set matDatepicker(value: MdDatepicker) { this.mdDatepicker = value; }

constructor(private _elementRef: ElementRef) {}
_onChange = (value: any) => {};

_onTouched = () => {};

private _datepickerSubscription: Subscription;

constructor(private _elementRef: ElementRef, private _renderer: Renderer,
private _locale: CalendarLocale) {}

ngAfterContentInit() {
if (this._datepicker) {
this._datepickerSubscription =
this._datepicker.selectedChanged.subscribe((selected: SimpleDate) => {
this.value = selected;
this._onChange(selected);
});
}
}

ngOnDestroy() {
if (this._datepickerSubscription) {
this._datepickerSubscription.unsubscribe();
}
}

getPopupConnectionElementRef(): ElementRef {
return this._elementRef;
}

// Implemented as part of ControlValueAccessor
writeValue(value: SimpleDate): void {
this.value = value;
}

// Implemented as part of ControlValueAccessor
registerOnChange(fn: (value: any) => void): void {
this._onChange = value => fn(this._locale.parseDate(value));
}

// Implemented as part of ControlValueAccessor
registerOnTouched(fn: () => void): void {
this._onTouched = fn;
}

// Implemented as part of ControlValueAccessor
setDisabledState(disabled: boolean): void {
this._renderer.setElementProperty(this._elementRef.nativeElement, 'disabled', disabled);
}
}
4 changes: 3 additions & 1 deletion src/lib/datepicker/datepicker.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<template>
<md-calendar
[class.mat-datepicker-touch]="touchUi"
[class.mat-datepicker-non-touch]="!touchUi">
[class.mat-datepicker-non-touch]="!touchUi"
[startAt]="startAt"
[(selected)]="_selected">
</md-calendar>
</template>
Loading

0 comments on commit 24dcc15

Please sign in to comment.