简体   繁体   中英

Angular 2: Form valid returns false until all fields are populated

I am using reactive forms.

I have a submit button that should be disabled until the form is valid:

<button type="submit" [disabled]="!_searchForm.valid && !_searchForm.pristine">Submit</button>

My fields can be toggled on/off using bools:

showName: boolean = true;
showPhone: boolean = true;
showCellphone: boolean = true;

And this is my validation rules:

this._searchForm = this._formBuilder.group({
    name: [{value: '', disabled: !this.showName}, Validators.compose([Validators.minLength(3), Validators.maxLength(50), Validators.pattern('^[a-zA-Z]+$')])],
    phone: [{value: '', disabled: !this.showPhone}, Validators.compose([Validators.minLength(3), Validators.maxLength(50), Validators.pattern('^[0-9-]+$')])],
    cellphone: [{value: '', disabled: !this.showCellphone}, Validators.compose([Validators.minLength(3), Validators.maxLength(50), Validators.pattern('^[0-9]+$')])]
});

And finally, this is how each field is displayed in the HTML:

<div class="form-group" [ngClass]="{'has-danger': _searchForm.controls.name.errors && !_searchForm.controls.name.pristine}">

<label for="name">Name:</label>

<div class="input-group">

    <span class="input-group-addon">
        <div class="onofwrapper">
            <div class="onoffswitch">
                <input id="toggleName" type="checkbox" class="onoffswitch-checkbox" (click)='toggleName()' [checked]="showName">
                <label class="onoffswitch-label" for="toggleName"></label>
            </div>
        </div>
    </span>

    <input type="text" formControlName="name" class="form-control" [ngClass]="{'form-control-danger': _searchForm.controls.name.errors && !_searchForm.controls.name.pristine}" autocomplete="off" spellcheck="false">

</div>

<div *ngIf="_searchForm.controls.name.errors && !_searchForm.controls.name.pristine" class="form-control-feedback">Error message</div>

If I don't touch the form I can submit, so pristine seems to be working.

The problem is, I can't enter text in just a single field and submit. If I enter text in one field, I have to enter text in all of them to be able to submit, or else _searchForm.valid won't return true even though I am not using Validators.required on all fields.

I have verified that each input "ships its own value", by removing the [disabled="!_searchForm.valid" line, and then just dumping out the values in my submit function like this:

console.log('Name: ' + this._searchForm.value.name);
console.log('Phone: ' + this._searchForm.value.phone);
console.log('Cellphone: ' + this._searchForm.value.cellphone);

What am I doing wrong? Why does .valid require all fields in the form?

If you disable or enable an input, then, you need a function:

enableDisableInput(inputName: string): void {
    if(!this._searchForm.controls[inputName].disabled) {
        this._searchForm.controls[inputName].clearValidators();
        this._searchForm.controls[inputName].disable();
    } else {
    this._searchForm.controls[inputName].setValidators(Validators.compose([Validators.minLength(3), Validators.maxLength(50), Validators.pattern('^[0-9]+$')])]);
    }
    this._searchForm.controls[inputName].updateValueAndValidity();
}

Invoked <input id="toggleName" type="checkbox" class="onoffswitch-checkbox" (click)='enableDisableInput("name")' [checked]="showName">

The manner in which the form building and validation is done with Reactive Forms means that you must manually clear and add validation even on disabled items (there may be plans to change this as it is a not uncommon complaint on the angular github). This is a code oriented and driven manner of forms and needs to be treated as such for the time being.

Whether or not the inputs are required is moot if they have an unmet minimum length. Reference https://github.com/angular/angular/pull/11450 which was recently included in Angular 2.0.2 https://github.com/angular/angular/blob/master/CHANGELOG.md

For forms driven it looks like they have a correction in 2.1.0 where those fields are optional with pattern and minlength but I don't know if that's also in Reactive Forms or not.

It turns out that this was a problem with input type="number" . The fields containing phone and cellphone values was only supposed to contain numbers, so in addition to the Validators.pattern('^[0-9-]+$') validation I also gave them the input type of number.

As soon as that was changed into text, everything worked like expected.

I had the same issue with the Angular reactive forms. I was disabling and enabling my form controls based on some logic. It turns out I was disabling, but not enabling back the form controls, so I was getting a form.valid as false. Apparently in Angular's reactive forms a form with disabled fields is invalid and the docs are not mentioning this default behavior.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM