L08084のブログ

技術記事の執筆は祈りに似ている

Angular + Firebase でアカウント登録画面の作成

AngularでFirebase認証(その1) Firebaseのセットアップ - L08084のブログ

AngularでFirebase認証(その2) Angular Materialを使ったログイン画面の作成 - L08084のブログ

AngularでFirebase認証(その3) Firebase Authentication の呼び出し - L08084のブログ

上の3記事で作成したAngular + FirebaseのWebアプリにアカウント登録機能を追加していきます。

メールアドレスとパスワードを使用したログイン機能については上の記事で既に実装済みです。

アカウント登録画面の作成

CSSフレームワークのAngular Materialを使ってアカウント登録画面の見た目から作っていきます。

Angular CLIベースのプロジェクトなので、下記のコマンドでアカウント登録画面Componentの一式を作成できます。

ng generate component sign-up

CLIで作成したファイルにレイアウトとバリデーションの処理を書いていきます。

  • sign-up.component.html
<app-header></app-header>
<div class="wrapper">
  <mat-card class="sign-up-card">
    <mat-card-header>
      <mat-card-title class="sign-up-title">Create an account</mat-card-title>
    </mat-card-header>
    <mat-card-content>
      <form (ngSubmit)="onSubmit()" class="sign-up-form" [formGroup]="signUpFormGroup">
        <mat-form-field>
          <input matInput placeholder="user name" id="userName" formControlName="userName" required>
          <mat-error *ngIf="userNameControl.invalid">{{getErrorMessageToUserName()}}</mat-error>
        </mat-form-field>
        <mat-form-field>
          <input matInput placeholder="email" id="email" formControlName="email" required>
          <mat-error *ngIf="emailControl.invalid">{{getErrorMessageToEmail()}}</mat-error>
        </mat-form-field>

        <mat-form-field>
          <input [type]="hide ? 'password' : 'text'"
            matInput placeholder="password" id="password" formControlName="password" required>
          <mat-icon matSuffix (click)="hide = !hide">{{hide ? 'visibility' : 'visibility_off'}}</mat-icon>
          <mat-error *ngIf="passwordControl.invalid">{{getErrorMessageToPassword()}}</mat-error>
        </mat-form-field>
        <mat-form-field>
          <input [type]="hideConfirm ? 'password' : 'text'"
            matInput placeholder="confirm password" id="confirmPassword" formControlName="confirmPassword" required>
          <mat-icon matSuffix (click)="hideConfirm = !hideConfirm">{{hideConfirm ? 'visibility' : 'visibility_off'}}</mat-icon>
          <mat-error *ngIf="confirmPasswordControl.invalid">{{getErrorMessageToConfirmPassword()}}</mat-error>
        </mat-form-field>
        <button type="submit" class="sign-up-button" mat-raised-button [disabled]="!signUpFormGroup.valid" color="primary">Create your account</button>
      </form>
    </mat-card-content>
  </mat-card>
</div>

アカウント登録画面のHTMLファイルです。アカウント名、メールアドレス、パスワードと確認用パスワードのフォームを設定しています。

  • sign-up.component.ts
import { Component, OnInit } from '@angular/core';
import {
  FormGroup,
  FormControl,
  FormBuilder,
  Validators
} from '@angular/forms';
import { AngularFireAuth } from '@angular/fire/auth';
import { Router } from '@angular/router';
import { CustomValidator } from '../validation/custom-validator';

@Component({
  selector: 'app-sign-up',
  templateUrl: './sign-up.component.html',
  styleUrls: ['./sign-up.component.scss']
})
export class SignUpComponent implements OnInit {
  // FormGroup定義
  public signUpFormGroup: FormGroup;
  public userNameControl: FormControl;
  public emailControl: FormControl;
  public passwordControl: FormControl;
  public confirmPasswordControl: FormControl;

  constructor(
    private fb: FormBuilder,
    private afAuth: AngularFireAuth,
    private router: Router
  ) {}

  public ngOnInit() {
    this.createForm();
    this.userNameControl = this.signUpFormGroup.get('userName') as FormControl;
    this.emailControl = this.signUpFormGroup.get('email') as FormControl;
    this.passwordControl = this.signUpFormGroup.get('password') as FormControl;
    this.confirmPasswordControl = this.signUpFormGroup.get(
      'confirmPassword'
    ) as FormControl;
  }

  /**
   * アカウント登録ボタン押下時に呼び出し
   *
   */
  public onSubmit() {
  }

  /**
   * ユーザーネームフォームにバリデーションエラーメッセージを表示
   *
   */
  public getErrorMessageToUserName() {
    return this.userNameControl.hasError('required')
      ? 'You must enter a value'
      : '';
  }

  /**
   * Eメールフォームにバリデーションエラーメッセージを表示
   *
   */
  public getErrorMessageToEmail() {
    return this.emailControl.hasError('required')
      ? 'You must enter a value'
      : this.emailControl.hasError('email')
      ? 'Not a valid email'
      : '';
  }

  /**
   * パスワードフォームにバリデーションエラーメッセージを表示
   *
   */
  public getErrorMessageToPassword() {
    return this.passwordControl.hasError('required')
      ? 'You must enter a value'
      : '';
  }

  /**
   * 確認用パスワードフォームにバリデーションエラーメッセージを表示
   *
   */
  public getErrorMessageToConfirmPassword() {
    return this.confirmPasswordControl.hasError('required')
      ? 'You must enter a value'
      : this.confirmPasswordControl.hasError('notMatchPassword')
      ? 'Password and confirm password do not match'
      : '';
  }

  /**
   * フォーム設定の作成
   *
   */
  private createForm() {
    this.signUpFormGroup = this.fb.group(
      {
        userName: ['', [Validators.required]],
        email: ['', [Validators.required, Validators.email]],
        password: ['', [Validators.required]],
        confirmPassword: ['', [Validators.required]]
      },
      {
        // パスワードと確認パスワードが一致しているか確認するバリデーション
        validator: CustomValidator.matchPassword
      }
    );
  }
}

アカウント登録画面のコンポーネントクラスです。Angularのリアクティブフォームの設定とバリデーション処理を記載しています。

パスワードと確認用パスワードが一致しているか確認するバリデーションは下記のファイルに分けて書いています。

  • custom-validator.ts
import { AbstractControl } from '@angular/forms';

export class CustomValidator {
  // パスワードと確認用パスワードが一致するかチェック
  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 });
    }
  }
}
  • sign-up.component.scss
.wrapper {
  display: flex;
  justify-content: center;
  align-items: center;
  margin-top: 15%;

  .sign-up-card {
    width: 500px;
  }

  .sign-up-form {
    display: flex;
    flex-direction: column;

    .sign-up-button {
      margin-top: 20px;
    }
  }

  .sign-up-title {
    font-weight: bold;
    font-size: 22px;
    color: #3f51b5;
  }
}

アカウント登録画面のCSSファイルです。ログイン画面のものをそのまま流用しています。

f:id:l08084:20190825154003p:plain
アカウント登録画面

ここまでのコードを実行すると、上記の画面が表示されます。

アカウント登録

AngularFireライブラリを使って、アカウント登録処理を書いていきます。

  • sign-up.component.ts
  /**
   * アカウント登録ボタン押下時に呼び出し
   *
   */
  public onSubmit() {
    this.afAuth.auth
      // Firebaseのアカウント登録処理の呼び出し
      .createUserWithEmailAndPassword(
        this.emailControl.value,
        this.passwordControl.value
      )
      .then(created => {
        const newUser = created.user;
        // 作成したアカウントにdisplayNameを設定する
        newUser
          .updateProfile({
            displayName: this.userNameControl.value,
            photoURL: ''
          })
          .then(() => {
            // アカウント登録処理が成功したらログイン画面に戻る
            this.router.navigate(['/login']);
          });
      });
  }

まず Firebase AuthenticationのcreateUserWithEmailAndPasswordを呼び出してアカウントを登録します。

createUserWithEmailAndPasswordが成功した後に、updateProfileを呼び出してアカウント名の設定をしています。アカウント名の設定が成功したら、ログイン画面への遷移処理を呼び出します。

動作確認

f:id:l08084:20190825154003p:plain
アカウントの登録

試しにアカウントを登録してみます。

f:id:l08084:20190825162722p:plain
作成したアカウントでログイン

ログイン画面に登録したアカウントのメールアドレスとパスワードを入力すると...

f:id:l08084:20190825162842p:plain
ログイン成功

ログインに成功します。

バージョン情報

  • Angular v7.2.0
  • firebase: v6.3.4
  • Angular Material v7.3.7

参考サイト

Firebase のユーザーを管理する  |  Firebase