06
2017

Angular2でパスワード再入力みたいなバリデーションを作る(改)

CATEGORYJavaScript
Angular2/4の標準のバリデータには、複数のフォームを比較するみたいなものは用意されてないっぽいので、それの作り方。
イケてないバージョンを経て、ng2-validation のソース見て作成。というかもう ng2-validation の equalTo 再実装して解説に近いけど以下解説。

まず最初にサンプルソースの抜粋から。こんな感じ。

equals-validator.directive.ts
import { Directive, Input, forwardRef, Attribute } from '@angular/core';
import { Validator, AbstractControl, FormControl, NG_VALIDATORS } from '@angular/forms';

@Directive({
selector: '[validateEquals][formControlName],[validateEquals][formControl],[validateEquals][ngModel]',
providers: [
{ provide: NG_VALIDATORS, useExisting: forwardRef(() => EqualsValidator), multi: true }
]
})
export class EqualsValidator implements Validator {
@Input() validateEquals: FormControl;
private subscribe: boolean = false;

validate(c: AbstractControl): { [key: string]: any } {
if (!this.subscribe) {
this.validateEquals.valueChanges.subscribe(() => {
c.updateValueAndValidity();
});
}

let v = c.value;
if (v != this.validateEquals.value) {
return {
validateEquals: true
}
}
return null;
}
}

app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { SampleComponent } from './sample.component';
import { EqualsValidator } from './equals-validator.directive';

@NgModule({
imports: [
BrowserModule,
FormsModule,
],
declarations: [
SampleComponent,
EqualsValidator,
],
bootstrap: [SampleComponent]
})
export class AppModule { }

sample.component.ts
import { Component } from '@angular/core';
import { NgForm } from '@angular/forms';

@Component({
selector: 'sample-form',
templateUrl: 'app/sample.html',
})
export class SampleComponent {
sampleForm = { password: '', passwordConfirm: '' };

submit(): void {
console.log(this.sampleForm);
}
}

sample.html
<form #f="ngForm" (ngSubmit)="submit()" novalidate>
<input type="password" name="password" [(ngModel)]="sampleForm.password" #password="ngModel" required>
<div *ngIf="password.errors">
<div [hidden]="!password.errors.required">パスワードを入力してください</div>
</div>
<input type="password" name="passwordConfirm" [(ngModel)]="sampleForm.passwordConfirm" #passwordConfirm="ngModel" required [validateEquals]="password">
<div *ngIf="passwordConfirm.errors">
<div [hidden]="!passwordConfirm.errors.required">確認用パスワードを入力してください</div>
<div [hidden]="!passwordConfirm.errors.validateEquals">確認用パスワードが一致しません</div>
</div>
<button type="submit" [disabled]="!f.form.valid">送信</button>
</form>

暇な人は旧版と比較してみてください。で、解説。
バリデータはまず @Input() により比較対象の要素を FormControl の形で貰う。
バリデータはそのままだと設定した要素が更新された時しか機能しないので、valueChanges のイベントを使って、対向側が更新された時も呼ばれるようにする。
subscribe プロパティは単に二重登録の抑止用。)

後は、HTML側で [validateEquals]="password" のように値ではなく変数自身を渡してあげればOK。
うむ、仕組みが分かってしまえば簡単ですね。なんか前ぐだぐだ書いたような気がするけど忘れてください(--;

応用すれば、日付比較とかいろいろできるはずなのでレッツトライ!
スポンサーサイト

Tag: JavaScript TypeScript Angular

0 Comments

Leave a comment