form example angular angular2-forms

example - tocado/intacto no se actualiza en el componente de entrada personalizado-Angular 2



angular reactive forms validation (2)

Tengo un componente de entrada personalizado que está actualizando la validación y los estados con la excepción de tocar / intacto. Todo lo demás en estado (prístino / sucio) funciona como se espera.

Aquí hay un plunker: 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; } }

¡Gracias por cualquier ayuda!


Estaba cometiendo dos errores, como un pomo. Así que la plantilla debe ser:

<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>

Entonces, las dos cosas donde (blur)="onTouched($event)" en la entrada, y el <p *ngIf="control?.errors?.required && control?.touched">


Simplemente pisé la respuesta de @sharpmachine y me ayudó a resolver mi problema. Solo me gustaría mejorarlo:

En lugar de tener que vincular el evento de blur a onTouched() en el nivel de plantilla (que puede ser propenso a errores), es posible exponer el ControlValueAccessor como una Directive y vincular el evento allí.

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; } }

De esta manera, debería poder usar el componente sin tener que vincular el evento de blur cada vez que lo use.

¡Espero eso ayude!