はじめに
アカウント登録画面を作っていて出現頻度が著しく高い項目といえば............そう!パスワードの入力フォームですね。というわけで今回は、パスワードと確認用パスワードが一致しているか確認するバリデーションを実装していきます。
そもそもAngularでカスタムバリデーションをどう作っていいかわからねーよという人は下記の記事を!
【JavaScript】文字列の間に空白(スペース)が入力されているか確認する(氏名などのバリデーション) - 中安拓也のブログ
Angular Materialのインストール方法と使い方については、下記の記事を参照してください。
Angular Material の Tableを使う - 中安拓也のブログ
Angular Materialでログインフォームを作る - 中安拓也のブログ
バリデーション内容
パスワードについてのバリデーションを設定します。チェックする項目は下記とします。
- パスワード欄と確認用パスワード欄で入力された内容が一致する
バージョン情報
JavaScriptのフレームワークとしてはAngularを、CSSのフレームワークとしてはAngular Materialを使用しています。
- Angular@7.0.6
- typescript@3.1.6
- webpack@4.19.1
- Angular Material@7.0.4
実装
パスワード入力フォーム作成
前回の記事で作成した入力フォームにコードを足していく感じで実装していきます。
コードが多くなってきて前回からの更新部分がわかりづらいですが、<!-- add this! -->
とコメントされている行が追加された部分になります。
まずテンプレートに、パスワード入力フォームと確認用パスワードの入力フォーム、そしてパスワードが表示しないときに表示するエラーメッセージを表示します。
app.component.html
<div class="container">
<mat-card class="login-card">
<mat-card-header>
<mat-card-title class="login-title">アカウント登録</mat-card-title>
</mat-card-header>
<mat-card-content>
<form [formGroup]="nameRegisterForm" (ngSubmit)="onSubmit()" class="login-form">
<mat-form-field class="input-field">
<input matInput placeholder="氏名(姓と名の間にスペースを入力してください)"
id="name" name="name" [formControl]="nameRegisterForm.controls.name" required>
<mat-error *ngIf="nameRegisterForm.controls.name.errors?.required">氏名は必須項目です</mat-error>
<mat-error *ngIf="nameRegisterForm.controls.name.errors?.haveBlank">姓と名の間にはスペースを入力してください</mat-error>
</mat-form-field>
<mat-form-field class="input-field">
<input [type]="hide ? 'password' : 'text'" matInput
placeholder="パスワード" id="password" name="password" [formControl]="nameRegisterForm.controls.password" required>
<mat-icon matSuffix (click)="hide = !hide">{{hide ? 'visibility' : 'visibility_off'}}</mat-icon>
<mat-error *ngIf="nameRegisterForm.controls.password.errors?.required">パスワードは必須項目です</mat-error>
</mat-form-field>
<mat-form-field class="input-field">
<input [type]="hide ? 'confirmPassword' : 'text'" matInput
placeholder="確認用パスワード" id="confirmPassword" name="confirmPassword" [formControl]="nameRegisterForm.controls.confirmPassword" required>
<mat-icon matSuffix (click)="hide = !hide">{{hide ? 'visibility' : 'visibility_off'}}</mat-icon>
<mat-error *ngIf="nameRegisterForm.controls.confirmPassword.errors?.required">確認用パスワードは必須項目です</mat-error>
<mat-error *ngIf="nameRegisterForm.controls.confirmPassword.errors?.notMatchPassword">パスワードが一致しません</mat-error>
</mat-form-field>
<button type="submit" class="register-button"
mat-raised-button color="primary" [disabled]="nameRegisterForm.invalid">登録</button>
</form>
</mat-card-content>
</mat-card>
</div>
コンポーネントクラスにもパスワード入力フォームに関するコードを追加します。(テンプレートの時と同じく追加部分には// add this!
とコメントしています)
app.component.ts
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, FormControl, Validators } from '@angular/forms';
import { CustomValidator } from './custom-validator';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
public nameRegisterForm: FormGroup;
public nameControl: FormControl;
public passwordControl: FormControl;
public confirmPasswordControl: FormControl;
public hide = true;
constructor(private builder: FormBuilder) {
this.createForm();
}
public ngOnInit(): void {
this.nameControl = this.nameRegisterForm.get('email') as FormControl;
this.passwordControl = this.nameRegisterForm.get('password') as FormControl;
this.confirmPasswordControl = this.nameRegisterForm.get('confirmPassword') as FormControl;
}
public onSubmit() {
console.log();
}
private createForm() {
this.nameRegisterForm = this.builder.group({
name: ['', [Validators.required, CustomValidator.haveBlank]],
password: ['', [Validators.required]],
confirmPassword: ['', [Validators.required]]
}, {
validator: CustomValidator.matchPassword
});
}
}
今回追加するのは複数項目に対するバリデーションなので、他のバリデーションと違ってvalidator: CustomValidator.matchPassword
という風にフォーム全体にバリデーションを定義しています。
最後にパスワード入力フォームに入力された内容と確認用パスワードに入力された内容が一致していることを確認するカスタムバリデーションmatchPassword
メソッドを追加します。
custom-validator.ts
import { ValidationErrors, FormControl, AbstractControl } from '@angular/forms';
export class CustomValidator {
static haveBlank(control: FormControl): ValidationErrors | null {
const value = (control.value || '') + '';
const name = value.trim();
const NAME_COLUMN_SPRIT_VALUE = ' ';
const NAME_COLUMN_SPRIT_VALUE_W = ' ';
let isError = false;
if (name.indexOf(NAME_COLUMN_SPRIT_VALUE) < 0
&& name.indexOf(NAME_COLUMN_SPRIT_VALUE_W) < 0) {
isError = true;
}
return isError ? { haveBlank: true } : null;
}
static matchPassword(ac: AbstractControl) {
const password = ac.get('password').value;
const passwordConfirm = ac.get('confirmPassword').value;
if (password !== passwordConfirm) {
ac.get('confirmPassword').setErrors({ notMatchPassword: true });
}
}
}
単項目に対するバリデーションであるhaveBlank
には引数としてFormControl
を渡していますが、複数項目に対するバリデーションであるmatchPassword
にはAbstractControl
を渡しています。
動作確認
書いたコードを動かしてみます
一致しないパスワードを入力するとエラーが表示されます。
一致するパスワードを入力するとエラーが表示されなくなるので、バリデーションが正しく機能していることがわかります。