我编写了一个简单的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-dirty,而不是ng-pristine.
解决方法
您可以使用ngControl.control属性将控件标记为实现ControlValueAccessor本身的组件的原始(或脏,触摸,未触摸):
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
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。