I wrote a simple CustomValueAccessor to implement pikaday datepicker. It works, but when I select a date with a date picker and update the property, the internal input control (which is bound to the property using ngModel) does not update its ng-primitive class, but the external component does. I need the internal input to be marked as ng-touch, and I cannot figure out how to achieve this.
Here is my class:
import { Component, OnInit, Input, Output, EventEmitter, ViewEncapsulation, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { DateService } from "./shared";
import * as pikaday from 'pikaday'
@Component({
selector: 'datepicker',
templateUrl: 'datepicker.component.html',
styles: [require('pikaday/css/pikaday.css')],
encapsulation: ViewEncapsulation.None,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DatePickerComponent),
multi: true
}
]
})
export class DatePickerComponent implements OnInit, ControlValueAccessor {
@Input() id: string;
@Input() minDate: Date = new Date();
@Output('date') dateChanged: EventEmitter<string> = new EventEmitter<string>();
private _date: string;
constructor() { }
ngOnInit() {
if(!this.id)
throw "Id is required for datepicker"
let options = {
field: document.getElementById(this.id),
format: DateService.datePickerFormat,
onSelect: date => {
this.date = startDatePicker.toString();
}
};
if(this.minDate)
options['minDate'] = this.minDate;
let startDatePicker = new pikaday(options);
}
set date(value){
this._date = value;
this.onChangeCallback(value);
this.onTouchedCallback(value);
}
get date(){
return this._date;
}
onChangeCallback = (_: any) => {};
onTouchedCallback = (_: any) => {};
registerOnChange(fn) {
this.onChangeCallback = fn;
}
registerOnTouched(fn) {
this.onTouchedCallback = fn;
}
writeValue(value: any) {
this.date = value;
}
}
And the template:
<input type="text" [id]="id" [(ngModel)]="date">
And here is the HTML before setting the value with datepicker:
<datepicker formcontrolname="endDatePicker" id="endDatePicker" ng-reflect-id="endDatePicker" ng-reflect-name="endDatePicker" class="ng-untouched ng-pristine ng-invalid"><input type="text" ng-reflect-model="" ng-reflect-id="endDatePicker" id="endDatePicker" class="ng-untouched ng-pristine ng-valid">
<input type="text" ng-reflect-model="" ng-reflect-id="endDatePicker" id="endDatePicker" class="ng-untouched ng-pristine ng-valid">
</datepicker>
And then this then:
<datepicker formcontrolname="endDatePicker" id="endDatePicker" ng-reflect-id="endDatePicker" ng-reflect-name="endDatePicker" class="ng-touched ng-dirty ng-valid"><input type="text" ng-reflect-model="19 October, 2016" ng-reflect-id="endDatePicker" id="endDatePicker" class="ng-pristine ng-valid ng-touched">
<input type="text" ng-reflect-model="19 October, 2016" ng-reflect-id="endDatePicker" id="endDatePicker" class="ng-pristine ng-valid ng-touched">
</datepicker>
Note the classes: ng-pristine and ng-touch on the input control. As far as I know, it should be ng-dirty, not ng-untouched.