Search code examples
angularangular2-formsangular4-forms

Angular4 Exclude Property from dirty check


I've implemented a custom form control via template driven forms which wraps an input in html and adds a label, etc. It talks to the form just fine with the 2way data binding on the ngModel. The problem is, the form is automatically marked as dirty when it is initialized. Is there a way to prevent this from happening so I can use those properties on the form and they will be accurate?

Custom selector (This works fine other than automatically being marked dirty):

<form class="custom-wrapper" #searchForm="ngForm">
            {{searchForm.dirty}}
            {{test}}
            <custom-input name="testing" id="test" label="Hello" [(ngModel)]="test"></custom-input>
            <pre>{{ searchForm.value | json }}</pre>
</form>

Custom input template:

<div class="custom-wrapper col-xs-12">
    <div class="row input-row">
        <div class="col-xs-3 col-md-4 no-padding" *ngIf="!NoLabel">
            <label [innerText]="label" class="inputLabel"></label>
        </div>
        <div class="col-xs-9 col-md-8 no-padding">
            <input pInput name="cust-input" [(ngModel)]="value"  />
        </div>
    </div>
</div>

Custom Input Component:

import { ControlValueAccessor, NG_VALUE_ACCESSOR } from "@angular/forms";
import { Component, Input, forwardRef } from "@angular/core";

@Component({
    selector: "custom-input",
    template: require("./custom-input.component.html"),
    providers: [
        {
            provide: NG_VALUE_ACCESSOR,
            useExisting: forwardRef(() => QdxInputComponent),
            multi: true
        }
    ]
})

export class CustomInputComponent implements ControlValueAccessor {
    @Input("value") _value  = "";
    get value() {
        return this._value;
    }
    set value(val: string) {
        this._value = val;
        this.propagateChange(val);
    }
    @Input() noLabel: boolean = false;
    @Input() label: string = "Label required";
    
    propagateChange = (_: any) => {};

    writeValue(value) {
        if (value !== undefined) {
            this.value = value;
        }
    }
    registerOnChange(fn) {
        this.propagateChange = fn;
    }
    registerOnTouched(fn) {}

}


Solution

  • You propagate your change that is why it is marked dirty. Just adapt your writeValue function to not propagate the change because logically it should not create a change:

    export class CustomInputComponent implements ControlValueAccessor {
        @Input("value") _value  = "";
        get value() {
            return this._value;
        }
        set value(val: string) {
            this._value = val;
            this.propagateChange(val);
        }
        @Input() noLabel: boolean = false;
        @Input() label: string = "Label required";
    
        propagateChange = (_: any) => {};
    
        writeValue(value) {
            if (value !== undefined) {
                this._value = value;
            }
        }
        registerOnChange(fn) {
            this.propagateChange = fn;
        }
        registerOnTouched(fn) {}
    
    }
    

    Shortly: use this._value instead of this.value in your writeValue