web-dev-qa-db-ja.com

Angular2-ぼかしのFormControl検証

ユーザーが正しい電子メールアドレスを入力したことを確認するために、基本的な電子メール検証を追加することを検討しています。現在、以下の方法を使用して、ユーザーが入力すると検証が更新され、1文字を入力した後にエラーが発生すると奇妙に見えます。

validEmail(c: Control){
if(!c.value.match('[a-z0-9!#$%&\'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&\'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?')){
  return {
    validEmail: true
  };
}
return null;
}    

ctrlEmailAddress: Control = new Control('', Validators.compose([
Validators.required, this.validEmail]));

次に、angularJSのように、フィールドのぼかしで検証をトリガーできるかどうか疑問に思っていました。

ng-model-options="{ updateOn: 'blur' }"

私はhtml内の入力フィールドのぼかしオプションを知っていますが、これはコントロールをエラー状態にする方法がない限り、コントロールをエラーにしません。

誰かが正しい方向に私を向けるのを手伝ってもらえますか?

ありがとう。

編集:私はangularJSソリューションではなく、angular2ソリューションを探しています。

38
Reece Thompson

EDIT 2

Alex および 公式ドキュメント のように、Angularバージョン5.0.0には新しいオプションがありますngModel updateOn: 'blur'

this.email = new FormControl(null, {
   validators: Validators.required,
   updateOn: 'blur'
});

また、change(デフォルト)、blursubmitなどの他の更新オプションを使用できます。


オリジナル

フォーカスの検証全体を削除し、ぼかしイベントの後にそれを返すディレクティブを使用します。クリスティアン・デシャンの答えに基づいています。

私はぼかしでのみ有効性を更新するので、フォーカス前に値が無効だった場合、その後は無効になります。ただし、入力を開始すると、有効性が更新されます。

何らかの理由で順序のクリアが理にかなっているので、最初に非同期検証をクリアします。

提供された提案は役に立ちます=)

import { Directive } from '@angular/core';
import { NgControl } from '@angular/forms';

@Directive({
  selector: '[validate-onblur]',
  Host: {
    '(focus)': 'onFocus($event)',
    '(blur)': 'onBlur($event)'
  }
})
export class ValidateOnBlurDirective {
    private validators: any;
    private asyncValidators: any;
    constructor(public formControl: NgControl) {
    }
    onFocus($event) {
      this.validators = this.formControl.control.validator;
      this.asyncValidators = this.formControl.control.asyncValidator;
      this.formControl.control.clearAsyncValidators();
      this.formControl.control.clearValidators();
    }

    onBlur($event) {
      this.formControl.control.setAsyncValidators(this.asyncValidators);
      this.formControl.control.setValidators(this.validators);
      this.formControl.control.updateValueAndValidity();
    }
}

また、これに注意してください Angular 2 github thread onBlur検証について


EDIT 1

別の問題があります-フィールドをクリックして、クリックして離れた後、検証が呼び出されます。それに関する通知(またはサーバー呼び出し)がある場合は、通知を行うたびに表示されます。したがって、wasChangedプロパティを追加して、次のように使用できます。

    @Directive({
        selector: '[validate-onblur]',
        Host: {
            '(focus)': 'onFocus($event)',
            '(blur)': 'onBlur($event)',
            '(keyup)': 'onKeyup($event)',
            '(change)': 'onChange($event)',
            '(ngModelChange)': 'onNgModelChange($event)'
        }
    })
    export class ValidationOnBlurDirective {
        private validators: any;
        private asyncValidators: any;
        private wasChanged: any;
        constructor(public formControl: NgControl) {
        }
        onFocus($event) {
            this.wasChanged = false;
            this.validators = this.formControl.control.validator;
            this.asyncValidators = this.formControl.control.asyncValidator;
            this.formControl.control.clearAsyncValidators();
            this.formControl.control.clearValidators();
        }
        onKeyup($event) {
            this.wasChanged = true; // keyboard change
        }
        onChange($event) {
            this.wasChanged = true; // copypaste change
        }
        onNgModelChange($event) {
            this.wasChanged = true; // ng-value change
        }
        onBlur($event) {
            this.formControl.control.setAsyncValidators(this.asyncValidators);
            this.formControl.control.setValidators(this.validators);
            if (this.wasChanged)
                this.formControl.control.updateValueAndValidity();
        }
    }
49
Alex Shestakov

Angular v 5.0.0の時点で、これはupdateOn: 'blur'をフォームコントロールにマークすることで可能になりました。

これは、ぼかしイベントが発生するまで、そのフォームコントロールに対してvalueChangesが起動しないことも意味します。 minlengthrequiredの例を次に示します。

this.form = new FormGroup({
  username: new FormControl('', {
  validators: [Validators.required, Validators.minLength(6)], updateOn: 'blur'} )
})

get username() {
  return this.form.get('username');
}

テンプレートでは、フィールドがtouchedでない限り、検証メッセージが表示されないようにマークする必要があります。

<div *ngIf="username.hasError('minlength') || username.hasError('required') 
              && username.touched">Required and minlength 6!
</div>

DEMO

P.S必要に応じて、特定のフォームコントロールだけでなく、フォーム全体にもマークを付けることができます

13
AJT_82

Rc6で方法を見つけました。

1-ディレクティブを作成します:validate-onblur.directive.ts

@Directive({
  selector: '[validate-onblur]',
  Host: {
    '(focus)': 'onFocus($event)',
    '(blur)': 'onBlur($event)'
  }
})
export class ValidateOnBlurDirective {
    constructor(public formControl: NgControl) {
    }

    onFocus($event) {
      this.formControl.control.markAsUntouched(false);
    }

    onBlur($event) {
      this.formControl.control.markAsTouched(true);
    }
}

次に、htmlテンプレートでフォームにディレクティブを追加するだけで、私の例ではReactiveFormsModuleモデルを使用します。

次に、これをエラーメッセージに追加します。

<input type="text" formControlName="full_name" validate-onblur />

<span *ngIf="formAccountDetails.controls.full_name.touched && !formAccountDetails.controls.full_name.valid && !formAccountDetails.controls.full_name.pristine" class="errors">
        ...
</span>
8

次のようなものを使用します:touchedのプロパティを使用ngControlオブジェクト。

 <div class="form-group" [class.has-error]="!name.valid && name.touched">
        <label for="name">Name</label>
        <input #name="ngForm" ngControl="name" name="name" type="text" class="form-control" required>
 </div>
7
tomasz

アレックスシェスタコフのソリューションを少し改善しました。これは、フォーカスを維持しながら値が変化したときにコントロール状態を有効に設定することを避けるために、既に機能しています。

@Directive({
    selector: '[validate-onblur]',
    Host: {
        '(focus)': 'onFocus($event)',
        '(blur)' : 'onBlur($event)'
    }
})
export class ValidateOnBlurDirective {

    private validators: any;
    private asyncValidators: any;
    private hasFocus = false;

    constructor(public formControl: NgControl) {
    }

    onFocus($event) {
        this.hasFocus = true;
        this.validators = this.formControl.control.validator;
        this.asyncValidators = this.formControl.control.asyncValidator;
        this.formControl.control.clearAsyncValidators();
        this.formControl.control.clearValidators();
        this.formControl.control.valueChanges
            .filter(() => this.hasFocus)
            .subscribe(() => this.formControl.control.markAsPending());
    }

    onBlur($event) {
        this.hasFocus = false;
        this.formControl.control.setAsyncValidators(this.asyncValidators);
        this.formControl.control.setValidators(this.validators);
        this.formControl.control.updateValueAndValidity();
    }
}

このようにして、コントロールはフォーカスを保持している限り、保留状態のままになります。これにより、コントロールがフォーカスを取得する前に無効になり、ユーザーが入力を開始するとすぐに、ぼかしイベントが発生する前に、バリデーターが再設定され、コントロールを決定する必要があります。