javascript – 如何在Custom ControlValueAccessor中更新ng-pristine

我编写了一个简单的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

相关文章

前言 做过web项目开发的人对layer弹层组件肯定不陌生,作为l...
前言 前端表单校验是过滤无效数据、假数据、有毒数据的第一步...
前言 图片上传是web项目常见的需求,我基于之前的博客的代码...
前言 导出Excel文件这个功能,通常都是在后端实现返回前端一...
前言 众所周知,js是单线程的,从上往下,从左往右依次执行,...
前言 项目开发中,我们可能会碰到这样的需求:select标签,禁...