簡體   English   中英

自定義表單控件(ControlValueAccessor)的綁定ngModel始終將表單設置為臟狀態

[英]Binding ngModel of custom form control (ControlValueAccessor) always sets form to dirty state

我正在嘗試實現一個非常簡單的自定義表單控件。

@Component({
    selector: 'text-input',
    template: '<input [(ngModel)]="value" />',
    providers: [{
        provide: NG_VALUE_ACCESSOR,
        useExisting: forwardRef(() => TextInputComponent),
        multi: true
    }]
})
export class TextInputComponent implements ControlValueAccessor {
    private _value: any;

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

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

    onChange = (x: any) => { };
    onTouched = () => { };
    registerOnChange(fn: (_: any) => void): void { this.onChange = fn; }
    registerOnTouched(fn: () => void): void { this.onTouched = fn; }
}

但我的問題是,當我在(反應)形式中使用它時,只需設置[(ngModel)] form.dirty計算為true ,但如果我使用普通輸入控件,則一切都按預期工作。

在此輸入圖像描述

<h2>Hello {{text}}</h2>

<form #f="ngForm" >
    <text-input [(ngModel)]="text" name="text"></text-input>
</form>

Dirty: {{f.dirty}}

<form #f2="ngForm" >
    <input [(ngModel)]="text" name="text" />
</form>

Dirty: {{f2.dirty}}

我的實施有問題嗎? 如何讓我的自定義控件以dirty的方式在交互發生時設置為true的方式工作?

Plunkr再現: https ://plnkr.co/edit/FBGAR4uqwen7nfIvHRaC p = preview

編輯:經過一些修補我終於找到了我認為應該是正確的實現。

我無法相信我從來沒有在網上找到一個很好的解釋onChangewriteValue函數如何對應臟/ prestine狀態以及如何處理重置。

一旦調用onChange您的控件將被設置為dirty: true 調用form.reset()將重置此狀態,但也調用writeValue來設置新值。 所以永遠不要在這種方法中調用onChange ,因為它會打破你的狀態。

在我的實現中,我為我的值設置了一個簡單的setter,我在其中調用onChange來實際設置正確的狀態,因為setter僅由我的模板中的輸入控件調用。

您的控件可能會更復雜地處理值實際更改的方式,但只要您實際調用onChange如果您想將更改反映到外部,您可以使用writeValue設置控件的值而不更改狀態一切都會好起來的。

@Component({
    selector: 'text-input',
    template: `<input [(ngModel)]="value"
                  (blur)="onTouched()" />`,
    providers: [{
        provide: NG_VALUE_ACCESSOR,
        useExisting: forwardRef(() => TextInputComponent),
        multi: true
    }]
})
export class TextInputComponent implements ControlValueAccessor {
    private _value: any;

    // NOTE: you could also just bind to a normal field without
    // getters and setters and call onChange from your template
    // e.g. from (ngModelChange) of the input control
    get value(): any { return this._value; }
    set value(value: any) {
        this.writeValue(value);
        this.onChange(value);
    }

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

    onChange(x: any) { console.log(x); }
    onTouch() { };
    registerOnChange(fn: (_: any) => void): void { this.onChange = fn; }
    registerOnTouched(fn: () => void): void { this.onTouched = fn; }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM