Checking whether an Angular2 form is valid or not

2019-04-06 00:52发布

问题:

I am trying to check whether a form is valid or not to prevent further execution if it is not.

Here is my form:

<form (ngSubmit)="updateFirstName(firstNameForm)" #firstNameForm="ngForm" novalidate>
    <div class="form-group" ng-class="getCssClasses(formCtrl, formCtrl.firstName)">
        <div class="input-group">
            <input type="text"
                   ngControl="firstName"
                   #firstName="ngForm"
                   required
                   minlength="2"
                   maxlength="35"
                   pattern_="FIRST_NAME_PATTERN"
                   [ngModel]="currentUserAccount?.firstName"
                   (ngModelChange)="currentUserAccount ? currentUserAccount.firstName = $event : null"
                   placeholder="{{'FIRST_NAME_FORM.NEW_FIRST_NAME'| translate }}"
                   class="form-control"/>
        </div>

        <div [hidden]="firstName.valid">
            <div *ngIf="firstName?.errors?.minlength" class="control-label">{{'FIRST_NAME_FORM.MIN_LENGTH'| translate}}</div>
        </div>
    </div>
    <div class="form-group">
        <button type="submit" class="btn btn-primary pull-right" [disabled]="buttonDisabled">{{'FIRST_NAME_FORM.SUBMIT'| translate}}</button>
        <a [routerLink]="['/dashboard/useraccount']" class="btn btn-link pull-right text-right">{{'FORM_CANCEL' | translate}}</a>
    </div>
</form>

However, when I submit an invalid form, I notice in the console that the valid attribute of NgForm is true...

 updateFirstName(firstNameForm) {
   console.log(firstNameForm);//the valid attribute of firstNameForm is true...
 }

Can anyone please let me know why this is the case?

回答1:

You are doing template driven forms. Please refer to this simple plunk

<h1>Employee Form</h1>
<form #personForm="ngForm" (submit)="personFormSubmit(personForm)" novalidate>
    <div>
        <div>
            <input id="nameInput" type="text" name="name"
                   ngControl="name"
                   required
                   minlength="2"
                   maxlength="35"
                   [(ngModel)]="person.name" />
        </div>
    </div> 
    <div>
      <button type="submit">Submit</button>
    </div>
    <div style="color: red">{{validationMessage}}</div>
</form>

and then the controller:

import { Component } from '@angular/core';
import { FORM_DIRECTIVES, ControlGroup, Control, Validators, FormBuilder, Validator, } from '@angular/common';
import 'rxjs/Rx';

export class Person {
    id: number;
    name: string;
}

@Component({
    selector: 'my-app',
    directives: [FORM_DIRECTIVES],
    templateUrl: 'app/app.component.html'
})
export class AppComponent {

    person: Person;
    validationMessage: string;

    constructor() {
        this.person = new Person();
        this.validationMessage = "";
    }

    personFormSubmit(personForm: ControlGroup) {
        if (personForm.valid) {
          this.validationMessage = "Form Is Valid";
        }
        else
        {
          this.validationMessage = "Form Is Not Valid";
        }
    }

}

If you want to move to more complex dynamic validation then it would be better to convert to Model driven Forms. As with this plunk



回答2:

That's the intended behavior

I found in the change log for 2.0.0-alpha.46 (2015-11-11)

Previously, the controlsErrors getter of ControlGroup and ControlArray returned the errors of their direct children. This was confusing because the result did not include the errors of nested children (ControlGroup -> ControlGroup -> Control). Making controlsErrors to include such errors would require inventing some custom serialization format, which applications would have to understand. Since controlsErrors was just a convenience method, and it was causing confusing, we are removing it. If you want to get the errors of the whole form serialized into a single object, you can manually traverse the form and accumulate the errors. This way you have more control over how the errors are serialized.

Then the docs for ControlGroup and ControlArray should be updated

See also https://github.com/angular/angular/issues/6504#issuecomment-171950667

You can check if firstNameForm.valid is false and then iterate the control groups and controls for errors.

The NgForm class has the errors property because it inherits from AbstractControlDirective but the errors from nested controls are not collected there.