首页 文章

如何在Custom ControlValueAccessor中更新ng-pristine

提问于
浏览
4

我编写了一个简单的CustomValueAccessor来实现pikaday datepicker . 它可以工作,但是当我选择带日期选择器的日期并更新属性时,内部输入控件(使用ngModel绑定到属性)不会更新它的ng-pristine类,而外部组件会更新 . 我需要将内部输入标记为ng-touching,我无法弄清楚如何实现这一点 .

这是我的 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: [
    // 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 .

1 回答

  • 0

    您可以使用 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

相关问题