【问题标题】:I want to display one error at a time with reactive forms and angular material我想使用反应形式和角度材料一次显示一个错误
【发布时间】:2019-01-19 06:08:24
【问题描述】:

我正在使用 Angular 反应形式和 Angular 材料。 我的代码运行良好。 但我想一次显示一个错误

我的 .html 文件代码

      <form [formGroup]="accountDetailsForm" novalidate (ngSubmit)="onSubmitAccountDetails(accountDetailsForm.value)">

        <mat-form-field class="full-width">
          <input matInput maxlength="25" placeholder="Username" formControlName="username" required>
          <mat-error *ngFor="let validation of account_validation_messages.username">
            <mat-error class="error-message" *ngIf="accountDetailsForm.get('username').hasError(validation.type) && (accountDetailsForm.get('username').dirty || accountDetailsForm.get('username').touched)">{{validation.message}}</mat-error>
          </mat-error>
        </mat-form-field>

        <mat-form-field class="full-width">
          <input matInput type="email" placeholder="Email" formControlName="email" required>
          <mat-error *ngFor="let validation of account_validation_messages.email">
            <mat-error class="error-message" *ngIf="accountDetailsForm.get('email').hasError(validation.type) && (accountDetailsForm.get('email').dirty || accountDetailsForm.get('email').touched)">{{validation.message}}</mat-error>
          </mat-error>
        </mat-form-field>


        <div formGroupName="matching_passwords">
          <mat-form-field class="full-width">
            <input matInput type="password" placeholder="Password" formControlName="password" required>
            <mat-error *ngFor="let validation of account_validation_messages.password">
              <mat-error class="error-message" *ngIf="accountDetailsForm.get('matching_passwords').get('password').hasError(validation.type) && (accountDetailsForm.get('matching_passwords').get('password').dirty || accountDetailsForm.get('matching_passwords').get('password').touched)">{{validation.message}}</mat-error>
            </mat-error>
          </mat-form-field>

          <mat-form-field class="full-width">
            <input matInput type="password" placeholder="Confirm Password" formControlName="confirm_password"  [errorStateMatcher]="parentErrorStateMatcher" required>
            <mat-error *ngFor="let validation of account_validation_messages.confirm_password">
              <mat-error class="error-message" *ngIf="(accountDetailsForm.get('matching_passwords').get('confirm_password').hasError(validation.type)|| accountDetailsForm.get('matching_passwords').hasError(validation.type)) && (accountDetailsForm.get('matching_passwords').get('confirm_password').dirty || accountDetailsForm.get('matching_passwords').get('confirm_password').touched)">{{validation.message}}</mat-error>
            </mat-error>
          </mat-form-field>

        </div>

        <mat-checkbox formControlName="terms">
          I accept terms and conditions
        </mat-checkbox>
        <mat-error *ngFor="let validation of account_validation_messages.terms">
          <mat-error class="error-message" *ngIf="accountDetailsForm.get('terms').hasError(validation.type) && (accountDetailsForm.get('terms').dirty || accountDetailsForm.get('terms').touched)">{{validation.message}}</mat-error>
        </mat-error>

        <button class="submit-btn" color="primary" mat-raised-button type="submit" [disabled]="!accountDetailsForm.valid">
          Submit
        </button>

      </form>

    

我的 .ts 文件代码

在这里,我为错误指定错误消息

account_validation_messages = {
    'username': [
      { type: 'required', message: 'Username is required' },
      { type: 'minlength', message: 'Username must be at least 5 characters long' },
      { type: 'maxlength', message: 'Username cannot be more than 25 characters long' },
      { type: 'pattern', message: 'Your username must contain only numbers and letters' },
      { type: 'validUsername', message: 'Your username has already been taken' }
    ],
    'email': [
      { type: 'required', message: 'Email is required' },
      { type: 'pattern', message: 'Enter a valid email' }
    ],
    'confirm_password': [
      { type: 'required', message: 'Confirm password is required' },
      { type: 'areEqual', message: 'Password mismatch' }
    ],
    'password': [
      { type: 'required', message: 'Password is required' },
      { type: 'minlength', message: 'Password must be at least 5 characters long' },
      { type: 'pattern', message: 'Your password must contain at least one uppercase, one lowercase, and one number' }
    ],
    'terms': [
      { type: 'pattern', message: 'You must accept terms and conditions' }
    ]
  }
  
 

表单验证器

 this.accountDetailsForm = this.fb.group({
      username: new FormControl('', Validators.compose([
       UsernameValidator.validUsername,
       Validators.maxLength(25),
       Validators.minLength(5),
       Validators.pattern('^(?=.*[a-zA-Z])(?=.*[0-9])[a-zA-Z0-9]+$'),
       Validators.required
      ])),
      email: new FormControl('', Validators.compose([
        Validators.required,
        Validators.pattern('^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$')
      ])),
      matching_passwords: this.matching_passwords_group,
      terms: new FormControl(false, Validators.pattern('true'))
    })

一切正常,但问题是我正在使用 ngFor 显示错误,但我想在 mat-error 的帮助下一次显示一个错误。

【问题讨论】:

    标签: angular angular-material mean angular6 angular-reactive-forms


    【解决方案1】:

    使用 css

    先隐藏所有错误

    mat-error {
      display: none;
    }
    

    然后只显示每个表单域的第一个错误:

    mat-form-field mat-error:first-child {
      display: block;
    }
    

    或者只是表单的第一个错误

    form mat-error:first-child {
      display: block;
    }
    

    【讨论】:

      【解决方案2】:

      请参考DEMO PROJECT 以获得更好的理解。

      control-message.component.ts:

      import { OnInit } from '@angular/core';
      import { Component, Input } from '@angular/core';
      import { FormGroup, FormControl, AbstractControl } from '@angular/forms';
      
      import { CustomValidationService } from '../custom-validation.service'
      
      @Component({
        selector: 'app-control-message',
        templateUrl: './control-message.component.html',
        styleUrls: ['./control-message.component.css']
      })
      export class ControlMessageComponent implements OnInit {
      
        ngOnInit() {
      
        }
        @Input() control: FormControl;
      
        constructor() { }
      
          /**
           * This method is use to return validation errors
           */
        get errorMessage() {
          for (let propertyName in this.control.errors) {
            if (this.control.errors.hasOwnProperty(propertyName) && this.control.touched) {
              return CustomValidationService.getValidatorErrorMessage(this.getName(this.control), propertyName, this.control.errors[propertyName]);
            }
            if (this.control.valueChanges) {
              return CustomValidationService.showValidatorErrorMessage(propertyName, this.control.errors[propertyName])
            }
          }
          return null;
        }
      
          /**
           * This method used to find the control name
           * @param control - AbstractControl
           */
        private getName(control: AbstractControl): string | null {
          let group = <FormGroup>control.parent;
      
          if (!group) {
            return null;
          }
      
          let name: string;
      
          Object.keys(group.controls).forEach(key => {
            let childControl = group.get(key);
      
            if (childControl !== control) {
              return;
            }
            name = key;
          });
      
          return name;
        }
      }
      

      control-message.component.html:

      <mat-error *ngIf="errorMessage !== null">
          {{errorMessage}}
      </mat-error>
      

      application-form.html:

      <h1>Common Error Message with Custom Validation Reactive Form</h1>
      
      <form [formGroup]="accountDetailsForm" novalidate (ngSubmit)="onSubmitAccountDetails(accountDetailsForm.value)">
          <div>
              <mat-form-field class="full-width">
                  <input matInput maxlength="25" placeholder="Username" formControlName="username" required>
              </mat-form-field>
              <app-control-message [control]="accountDetailsForm.controls.username"></app-control-message>
          </div>
      
          <div>
              <mat-form-field class="full-width">
                  <input matInput type="email" placeholder="Email" formControlName="email" required>
              </mat-form-field>
              <app-control-message [control]="accountDetailsForm.controls.email"></app-control-message>
          </div>
      
          <div>
              <mat-form-field class="full-width">
                  <input matInput type="password" placeholder="Password" formControlName="password" required>
              </mat-form-field>
              <app-control-message [control]="accountDetailsForm.controls.password"></app-control-message>
          </div>
          <div>
              <mat-form-field>
                  <input matInput type="password" placeholder="Confirm Password" formControlName="confirm_password" required>
              </mat-form-field>
      
              <app-control-message [control]="accountDetailsForm.controls.confirm_password"></app-control-message>
              <mat-error *ngIf="accountDetailsForm.controls.password.value != accountDetailsForm.controls.confirm_password.value">
                  Password & Confrm Password Did not matched.
              </mat-error>
          </div>
          <button class="submit-btn" color="primary" mat-raised-button type="submit" [disabled]="!accountDetailsForm.valid || (accountDetailsForm.controls.confirm_password != accountDetailsForm.controls.password)">
        Submit</button>
      </form>
      

      application-form.component.ts:

      accountDetailsForm: FormGroup;
        constructor(private fb: FormBuilder) {
        }
        ngOnInit() {
          this.createForm()
        }
        onSubmitAccountDetails(val) {
          console.log(val);
        }
      
        createForm() {
          this.accountDetailsForm = this.fb.group({
            username: ['', [
              Validators.maxLength(25),
              Validators.minLength(5),
              Validators.pattern('^(?=.*[a-zA-Z])(?=.*[0-9])[a-zA-Z0-9]+$'),
              Validators.required
            ]],
            email: [null, [
              Validators.required,
              Validators.pattern('^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$')
            ]],
            password: [null, Validators.required],
            confirm_password: [null, Validators.required]
          })
        }
      

      【讨论】:

        【解决方案3】:

        您可以在 ts 文件中使用 for 循环来查找错误。

        In your .ts File
        
        for (let c in this.account_validation_messages.controls) {
              this.account_validation_messages.controls[c].markAsTouched();
            }
        

        删除此 HTML 代码并

        <mat-error *ngFor="let validation of account_validation_messages.terms">
                  <mat-error class="error-message" *ngIf="accountDetailsForm.get('terms').hasError(validation.type) && (accountDetailsForm.get('terms').dirty || accountDetailsForm.get('terms').touched)">{{validation.message}}</mat-error>
                </mat-error>
        
        Replace with this:
        
        <mat-error class="error-message" *ngIf="accountDetailsForm.get('terms').hasError(validation.type) && (accountDetailsForm.get('terms').dirty || accountDetailsForm.get('terms').touched)">{{validation.message}}</mat-error>
        

        【讨论】:

          猜你喜欢
          • 2022-11-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-05-19
          • 2021-05-05
          • 2021-07-08
          • 1970-01-01
          • 2019-12-25
          相关资源
          最近更新 更多