Подтвердить что ты не робот

Коснулся/нетронутый, не обновлялся в пользовательском компоненте ввода - Angular 2

У меня есть пользовательский компонент ввода, который обновляет валидацию и состояния, за исключением затронутых/нетронутых. Все остальное по-государственному (первозданному/грязному) работает так, как ожидалось.

Здесь плункер: https://plnkr.co/edit/O9KWzwhjvySnXd7vyo71

import { Component, OnInit, Input, ElementRef, forwardRef, Renderer } from '@angular/core';
import { REACTIVE_FORM_DIRECTIVES, Validator, Validators, NG_VALUE_ACCESSOR, ControlValueAccessor} from '@angular/forms';



export const CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR: any = /*@ts2dart_const*/ {
  provide: NG_VALUE_ACCESSOR,
  useExisting: forwardRef(() => CustomInputComponent),
  multi: true
};

const noop = () => {};

@Component({
  selector: 'my-custom-input',
  providers: [CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR],
  template: `
  <div class="form-group">
    <label>CUSTOM INPUT</label>
    <input type="text" class="form-control" [(ngModel)]="value" required>
    <p *ngIf="control.errors.required && control.touched">Field is required</p>
    <strong>Has input been touched: {{control.touched ? 'Yes' : 'No'}}</strong><br>
    <strong>Is input untouched: {{control.untouched ? 'Yes' : 'No'}}</strong><br>
    <strong>Is input dirty: {{control.dirty ? 'Yes' : 'No'}}</strong> <br>
        <strong>Is input pristine: {{control.pristine ? 'Yes' : 'No'}}</strong>
  </div>
  <div>
    In Custom Component: {{value}}
  </div>
`
})


export class CustomInputComponent implements ControlValueAccessor {
  @Input() control;


  // The internal data model
  private _value: any = '';

  //Placeholders for the callbacks
  private _onTouchedCallback: (_:any) => void = noop;

  private _onChangeCallback: (_:any) => void = noop;

  //get accessor
  get value(): any { return this._value; };

  //set accessor including call the onchange callback
  set value(v: any) {
    if (v !== this._value) {
      this._value = v;
      this._onChangeCallback(v);
    }
  }

  //Set touched on blur
  onTouched(){
    this._onTouchedCallback(null);
  }

  //From ControlValueAccessor interface
  writeValue(value: any) {
    this._value = value;
  }

  //From ControlValueAccessor interface
  registerOnChange(fn: any) {
    this._onChangeCallback = fn;
  }

  //From ControlValueAccessor interface
  registerOnTouched(fn: any) {
    this._onTouchedCallback = fn;
  }

}

Спасибо за любую помощь!

4b9b3361

Ответ 1

Только что наступил на ответ @sharpmachine, и это помогло решить мою проблему. Я просто хотел бы улучшить его:

Вместо того, чтобы привязать событие blur к onTouched() на уровне шаблона (который может быть подвержен ошибкам), можно открыть ControlValueAccessor как Directive и связать событие там.

import { Directive, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

export const CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR: any = {
  provide: NG_VALUE_ACCESSOR,
  useExisting: forwardRef(() => CustomInputAccessor),
  multi: true
};

@Directive({
  selector: 'my-custom-input',
  host: {'(blur)': 'onTouched($event)'},
  providers: [CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR],
})
export class CustomInputAccessor implements ControlValueAccessor {

  // The internal data model
  private _value: any = '';

  public onChange: any = (_) => { /*Empty*/ }
  public onTouched: any = () => { /*Empty*/ }

  get value(): any { return this._value; };

  set value(v: any) {
    if (v !== this._value) {
      this._value = v;
      this.onChange(v);
    }
  }

  writeValue(value: any) {
    this._value = value;
  }

  registerOnChange(fn: any) {
    this.onChange = fn;
  }

  registerOnTouched(fn: any) {
    this.onTouched = fn;
  }
}

Таким образом, вы должны иметь возможность использовать компонент без привязки события blur каждый раз, когда вы его используете.

Надеюсь, что это поможет!

Ответ 2

Я делал две ошибки, как ручку. Таким образом, шаблон должен быть:

<div class="form-group">
    <label>CUSTOM INPUT</label>
    <input type="text" class="form-control" [(ngModel)]="value" (blur)="onTouched($event)" required>
    <p *ngIf="control?.errors?.required && control?.touched">Field is required</p>

    <strong>Has input been touched: {{control.touched ? 'Yes' : 'No'}}</strong><br>
    <strong>Is input untouched: {{control.untouched ? 'Yes' : 'No'}}</strong><br>
    <strong>Is input dirty: {{control.dirty ? 'Yes' : 'No'}}</strong> <br>
    <strong>Is input pristine: {{control.pristine ? 'Yes' : 'No'}}</strong>
  </div>
  <div>
    In Custom Component: {{value}}
  </div>

Итак, две вещи, где (blur)="onTouched($event)" на входе и <p *ngIf="control?.errors?.required && control?.touched">