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!