web-dev-qa-db-ja.com

Angular 2 / Material-md-親FormGroupに適用されたカスタムバリデーターでエラーが表示されない

Angular(v4.3.6)のモデル駆動型フォームに表示する検証エラーを取得するのに問題があります。

私のモデルには、次のものがあります。

this.registerForm = formBuilder.group({
        'email':[null,Validators.compose([Validators.required, ValidateEmail])],
        'firstName':[null, Validators.required],
        'lastName':[null, Validators.required],
        'passwordGroup': formBuilder.group({
            'password':[null, Validators.compose([Validators.required,Validators.minLength(8)])],
            'passwordConfirmation':[null, Validators.required],
        },{validator: ValidatePasswordConfirmation})
    });

参照されるValidatePasswordConfirmationカスタムバリデーターは次のとおりです。

export function ValidatePasswordConfirmation(group: FormGroup) {

    if(group.value.password !== group.value.passwordConfirmation){
        return { 'no-match':true };
    }

    return null;
}

最後に、私のテンプレートには次のものがあります。

<md-form-field>
  <input mdInput name="passwordConfirmation" placeholder="Confirm password" [formControl]="registerForm.controls['passwordGroup'].controls['passwordConfirmation']" [(ngModel)]="model.passwordConfirmation" type="password">

<md-error *ngIf="registerForm.controls['passwordGroup'].controls['passwordConfirmation'].hasError('required')">
    Password confirmation is required
  </md-error>

<md-error *ngIf="registerForm.controls['passwordGroup'].hasError('no-match')">
    Passwords don't match
  </md-error>

</md-form-field>

ただし、「一致なし」エラーによって管理されるmdエラーは表示されません。したがって、このページでこれをデバッグするために、次を追加しました。

no-match = {{registerForm.controls['passwordGroup'].hasError('no-match')}} 
invalid = {{registerForm.controls['passwordGroup'].invalid}}

当然のことながら、デバッグ行には予想どおりtrue/falseが表示されます。ただし、「md-error」は表示されません...「required」エラーが表示される場合を除きます。 [formControl]がpasswordConfirmationFormControlを参照していることが原因だと感じているので、無効にしないとmd-errorは表示されません。ただし、外部のFormGroupが無効な場合に、このエラーを表示したいと思います。

ここで私がどこで間違っているのかについてのポインタは本当に役に立ちます!

最後に、PasswordConfirmation FormControlでエラーを設定するなど、これを回避する他のいくつかの方法を試しましたが、現在の実装が失敗する理由を知りたいと思います。

7
user1615376

カスタムErrorStateMatcherを使用してまったく同じ問題を解決できることがわかりました(デフォルトでは、エラーを表示する前にコントロールが無効な状態である必要があります)

export class ParentErrorStateMatcher implements ErrorStateMatcher {
    isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
        const isSubmitted = !!(form && form.submitted);
        const controlTouched = !!(control && (control.dirty || control.touched));
        const controlInvalid = !!(control && control.invalid);
        const parentInvalid = !!(control && control.parent && control.parent.invalid && (control.parent.dirty || control.parent.touched));

        return isSubmitted || (controlTouched && (controlInvalid || parentInvalid));
    }
}

これは、私のページコンポーネントで変数として公開されています...

@Component({
    templateUrl: 'register.page.component.html',
    styleUrls: ['register.page.styles.css']
})
export class RegisterPageComponent implements OnInit {
    registerForm: FormGroup;
    parentErrorStateMatcher = new ParentErrorStateMatcher();

    // Accessors
    get name() { return this.registerForm.get('name'); }
    get email() { return this.registerForm.get('email'); }
    get passwords() { return this.registerForm.get('passwords'); }
    get password() { return this.registerForm.get('passwords.password'); }
    get confirmPassword() { return this.registerForm.get('passwords.confirmPassword'); }
...

このフォームで...

this.registerForm = this.formBuilder.group({
        name: ['', [
            Validators.required,
            Validators.maxLength(256)]
        ],
        email: ['', [
            Validators.email,
            Validators.required,
            Validators.maxLength(256)]
        ],
        passwords: this.formBuilder.group({
            password: ['', [
                Validators.required,
                Validators.maxLength(128)
            ]],
            confirmPassword: ['', [
                Validators.required
            ]]
        },
            {
                validator: CustomValidators.doNotMatch('password', 'confirmPassword')
            }),
    });

そして、パスワードフィールドのこのマークアップ(errorStateMatcherおよびconfirmPassword入力コントロールの最後のマットエラーを参照)...

<div formGroupName="passwords">
    <mat-form-field class="full-width">
        <input matInput placeholder="Password" type="password" name="password" id="password" formControlName="password" required/>
        <mat-error *ngIf="password.errors && password.errors.required">
            Please enter your password
        </mat-error>
        <mat-error *ngIf="password.errors && password.errors.maxLength">
            Password must be less than 128 characters long
        </mat-error>
    </mat-form-field>

    <mat-form-field class="full-width">
        <input matInput placeholder="Confirm Password" type="password" name="confirmPassword" id="confirmPassword" formControlName="confirmPassword" required
            [errorStateMatcher]="parentErrorStateMatcher"/>
        <mat-error *ngIf="confirmPassword.errors && confirmPassword.errors.required">
            Please confirm your password
        </mat-error>
        <mat-error *ngIf="passwords.errors && passwords.errors.doNotMatch">
            Passwords do not match
        </mat-error>
    </mat-form-field>
</div>

Materialを使用していなかったときよりも少し混乱しているように感じますが、トレードオフには満足しています。実際、追加のコードはカスタムマッチャーだけです:)

8

},{validator: ValidatePasswordConfirmation} on Angular Material inputのようなカスタム検証でこの問題にすでに遭遇しましたが、それはMaterialの問題のようです。これがAngular =マテリアルページ: https://github.com/angular/material2/issues/7084 。回答がないため、問題は引き続き発生しています。フォームの送信後に検証を使用することにしました。あまり美しくはありませんが、機能しています。次のリリースで問題が解決されることを願っています。

または、リアルタイムの検証が必要な場合は、次のようにすることができます。

checkArePasswordsValid() {
    this.passwordsAreEqual = this.passwordValue === this.passwordConfirmationValue ? true : false;
}

このブール値を検証に使用します。

0

私の場合、このコードは完全に正常に機能しています。コード構造は次のとおりです。

// component.ts
import { FormBuilder, FormGroup, FormControl, Validators } from '@angular/forms';

function validate(v: FormGroup): any {
  let a = k.get('a');
  let b = k.get('b');
  if (a.value != undefined && (b.value == undefined || a.value == "none" || b.value == " ")) {
    return { ab: true };
  }
  return null;
}

@Component({
})

export class component implements OnInit, OnDestroy {
  constructor(){}
  ngOnInit() {
    this.registerForm = formBuilder.group({
        'email':[null,Validators.compose([Validators.required, ValidateEmail])],
        'firstName':[null, Validators.required],
        'lastName':[null, Validators.required],
        'passwordGroup': formBuilder.group({
            'password':[null, Validators.compose([Validators.required,Validators.minLength(8)])],
            'passwordConfirmation':[null, Validators.required],
        },{validator: ValidatePasswordConfirmation})
    });
  }
}

条件の場合に表示されるHTMLエラーメッセージは、コードで前述したのと同じ方法で使用されます。

0
Tejal