2016-07-19 166 views
13

Ho un componente di input personalizzato che sta aggiornando la convalida e gli stati ad eccezione di touched/untouched. Tutto il resto dello stato (incontaminato/sporco) funziona come previsto.toccato/non toccato dall'aggiornamento nel componente di input personalizzato - Angular 2

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

} 

Grazie per qualsiasi aiuto!

risposta

8

appena messo piede sul @sharpmachine risposta e mi ha aiutato a risolvere il mio problema. Vorrei solo per migliorarla:

invece di dover legare l'evento blur-onTouched() a livello di modello (che può essere soggetto a errori) è possibile esporre il ControlValueAccessor come Directive e associare l'evento lì.

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

In questo modo si dovrebbe essere in grado di utilizzare il componente senza dover legare l'evento blur ogni volta che si utilizza.

Spero che aiuti!

+0

Grazie! Molto utile! – sharpmachine

4

Stavo facendo due errori, come un pomello. Così il modello deve essere:

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

Quindi le due cose in cui il (blur)="onTouched($event)" sull'ingresso e il <p *ngIf="control?.errors?.required && control?.touched">

+0

Naturalmente! Per qualche ragione, penso che l'implementazione dell'interfaccia ControlValueAccessor risolverà tutto ciò per me. Ehh. – lukeatdesignworks