我编写了一个简单的CustomValueAccessor来实现pikaday datepicker。它可以工作,但是当我选择带日期选择器的日期并更新属性时,内部输入控件(使用ngModel绑定到属性)不会更新它的ng-pristine类,而外部组件会更新。我需要将内部输入标记为ng-touching,我无法弄清楚如何实现这一点。
这是我的班级:
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: [
// providers to implement formControlName
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DatePickerComponent),
multi: true
}
]
})
export class DatePickerComponent implements OnInit, ControlValueAccessor {
/**
* ID of the input element
*/
@Input() id: string;
/**
* The minimum date the user can select. Defaults to today. Set to null to not require.
*/
@Input() minDate: Date = new Date();
/**
* Outputs the chosen date string
*/
@Output('date') dateChanged: EventEmitter<string> = new EventEmitter<string>();
/**
* The formatted date value
*/
private _date: string;
constructor() { }
/**
* Initialises the pikaday datepicker
*/
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);
}
/**
* Emits the new date
*/
set date(value){
this._date = value;
this.onChangeCallback(value);
this.onTouchedCallback(value);
}
/**
* Returns the date value
*/
get date(){
return this._date;
}
/**
* Push date to parent components (required by ControlValueAccessor)
*/
onChangeCallback = (_: any) => {};
/**
* let formControlValue interface register a touch callback
*/
onTouchedCallback = (_: any) => {};
/**
* Allows parent component to set the onchange handler
*/
registerOnChange(fn) {
this.onChangeCallback = fn;
}
/**
* Allows parent component to set an ontouch handler (not implemented)
*/
registerOnTouched(fn) {
this.onTouchedCallback = fn;
}
/**
* Called when the component is inited with formControlName
*/
writeValue(value: any) {
this.date = value;
}
}
模板:
<input type="text" [id]="id" [(ngModel)]="date">
以下是使用datepicker设置值之前的HTML:
<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>
这是事后:
<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>
注意输入控件上的类:ng-pristine和ng-touching。就我而言,它应该是肮脏的,而不是ng-pristine。
答案 0 :(得分:0)
您可以使用ControlValueAccessor
属性从实现ngControl.control
的组件中将控件标记为原始(或脏,触摸,未触摸):
export class DatePickerComponent implements ControlValueAccessor {
// ...
yourFunction(): void {
let control = this.ngControl.control;
// use any of these to manipulate the state of the control in the form
control.markAsTouched();
control.markAsUntouched();
control.markAsDirty();
control.markAsPristine();
}
}
ngControl.controle是Angular表单内部使用的AbstractControl对象。一些文档链接:https://angular.io/api/forms/AbstractControl