Angular5+Firebaseでチャットアプリを作る⑤ 完成編

この記事は次の記事の続きです。

Angular5+Firebaseでチャットアプリを作る④ 新規ユーザー登録編

また、この記事は次の教材を参考に作成しています。おすすめの教材です。

この教材がないと細々としたところはわからないと思います。

参考:【最新v5対応】はじめてのAngular入門 実践シングルページアプリケーション(SPA)構築 | Udemy

前回は、一つのコンポーネントに集約されていた機能を分散し、そしてルーティング設定とユーザー登録機能を実装しました。

今回はログイン・ログアウトの機能を実装していきます。

ログインを実装する

まずログイン機能から作っていきましょう。

ログインコンポーネント

次のコマンドを実行します。

コマンド ng g component login

教材からテンプレートとスタイルシートをコピペします。

login.component.html

login.component.css

ログインのルーティング設定

そして、ルーティングモジュールで前回のSign Inと同じようにルーティングを設定します。

前回:Angular5+Firebaseでチャットアプリを作る④ 新規ユーザー登録編 – まんくつ

正しく設定できていれば次のURLでログイン画面が表示されるようになります。

http://localhost:4200/login

さらに、ログインとサインインを行き来できるようにするため、htmlを一部書き換えます。

ログインhrmlの一番下の要素「アカウントを新規作成」のようにサインインにもルーターリンクを設定します。

これでログインとサインインの行き来ができるようになりました。

ログインとサインインの表示切り替え

まずは、ログインとログアウトの表示切り替えを実装していきます。

ログインとログアウト

ヘッダーコンポーネントを編集していきます。

クラス内で次のように宣言してログインの成否で表示を変えるようにしていきます。

login: boolean;

コンストラクターで次のように宣言します。

private afAuth: AngularFireAuth,
private authService: AuthService

さらに、ngOnInit()は次のように宣言します。

onAuthStateChanged:認証状態にの変化に応じて実行されるAngularFireAuthのメソッドです。引数userに値がある場合はログイン状態としてloginにtrueを返します。

変更をブラウザに反映させるためテンプレートに次のコードを追加します。

<a routerLink=”/” *ngIf=”login” class=”navbar-text text-dark” (click)=”logout()”>Logout</a>

同じようにSignUpにも*ngIf=”!login”を加えます。

この状態で実行されたアプリを見てみましょう。

前回、メールアドレスを登録したままなら右上がログアウトと表示されているはずです。

さらに、ログアウトをクリックすればログアウトになるように次のコードをヘッダーコンポーネントクラスに追加します。

logout(): void {
this.authService.logout();
}

ユーザー認証機能を実装したauthServiceで実際にログアウトするので、ここではサービスのログアウト関数を実行するように命令をだします。

ではサービスでログアウト機能を実装しましょう。

次のコードをサービスクラス内で定義します。

signOut:AngularFireAuthのサインアウトメソッドです。

ログアウトが完了したら、ログインページに遷移するようになります。

では次にログインも実装していきます。

ログアウトと同じようにサービスのクラス内に次のコードを追加します。

signInWithEmailAndPassword:AngularFireAuthのサインインのメソッドです。今回はログインとして使います。

このサービスをログインコンポーネントで使えるようにします。

ログインコンポーネントクラスに次のコードを定義します。

これは前回やったとおりですね。

フォームに入力されている入力値をサービスに渡します。

前回:Angular5+Firebaseでチャットアプリを作る④ 新規ユーザー登録編 – まんくつ

login(f: NgForm): void {
this.authService.login(f.value.email, f.value.password);
}

適宜、インポートとコンストラクターに定義を加えます。

さて、これで入力値が登録値と合っているかはまだ見ていませんが、ページ遷移の設定ができるようになりました。

では、大切な登録情報について見ていきましょう。

ユーザー詳細設定

まず、ユーザー情報を設定する画面を実装していきましょう。

ルーティングとして次のようになります。

  • /users/new → ユーザー情報入力画面
  • /users/:uid → ユーザーの詳細画面

これらをの機能を機能モジュールをusersとしてまとめて作ります。

では、次のコマンドを実行します。

コマンド  ng g module users

さらに新しくルーティングモジュールを作ります。

一つのルーティングファイルにすべて盛り込むとややこしくなるので分けたほうがわかりやすい、場合は分けます。

コマンド ng g module users/users-routing –flat –module=users

さらにコンポーネントを作成します。

コマンド  ng g component users/new-user

ユーザー情報入力用のコンポーネントになります。

では、ルーティングファイルから編集していきます。

ルーティングパスを設定します。

const routes: Routes = [
{ path: ‘new’, component: NewUserComponent }
];

そして、@NgModule.importsに次のコードを加えます。

RouterModule.forChild(routes)

forChild:子要素のルーティングモジュールメソッドです。

適宜、インポートや@NgModule内の追加を忘れずに。

子要素を読み込ませるために親要素をアップルーティングモジュールに加えます。

{ path: ‘users’, loadChildren: ‘app/users/users.module#UsersModule’ },

#UsersModule:モジュールのクラス名をシャープの後に続けます。

このように機能モジュールはパスで分けて扱います。

そのため、今回はuserを分けて作成しています。

パスで分けることで開発自体も分離して行うことができます。

機能ごとにルーティング設定も別に行うことで、loadChildrenによって読み込ませるだけで済むので複雑になりがちなコードを簡潔にできるし、エラーがあった場合どこが悪いかもわかりやすくなります。

ユーザー詳細設定機能

では、UsersModuleを設定していきます。

教材からテンプレートとスタイルシートをコピペします。

new-user.component.html

new-user.component.css

テンプレート内にngFormがあるので、ユーザーモジュールでFormsModuleのインポートを忘れずに。

これで次のURLを開けばユーザー情報登録画面がでてきます。

http://localhost:4200/users/new

この段階では名前だけとしておきます。

では、このページはサインインした人に表示するので、サービスのcreate().thennavigate内を次のように変えます。

‘/users/new’

これでサインイン後、ユーザー情報登録画面に遷移するようになりました。

ユーザー情報の登録

では、ユーザー情報が登録できるように機能を実装していきましょう。

まず、ユーザー登録のcreate()が認証のサービスの中に入っているので、これをユーザー機能として使えるようにしていきます。

次のコードを実行します。

コマンド ng g service core/service/user

この中にcreate()を移動します。

それに伴い、インポートやコンストラクターなど、必要なコードを記述します。

移動が終わったら、次はデータの更新用のupdate()も定義します。

  • currentUser:今、ログインしているユーザーが格納されているAngularFireAuthのメソッドです。ログインしていなければNULLが返されます。
  • updateProfile:メールやパスワードを変えることができるAngularFireAuthのメソッドです。
  • db.object:データベースの中から指定の配列を参照するAngularFireDatabaseメソッドです。
  • /users/${this.afAuth.auth.currentUser.uid}currentUser.uidで取得したユーザーIDを基にユーザーの詳細情報の場所
  • update(values):上書き保存。valuesは入力した名前です。

つまり、update()が実行されたとき、ユーザーのメールやパスワードを読み込み、そして、IDが一致するユーザーのユーザーネームを入力値のvaluesで上書き保存します。

では、これをnew-user.componentで実行するためにコードを追加します。

submitForm(f: NgForm): void {this.userService.update(f.value);}

適宜、インポートとコンストラクターを追加します。

これで、update()に入力値をクリックイベントで受け渡せるようになりました。

さらに、create()のサービスファイルが変わったので、create()を実行している、サインアップコンポーネントのインポートを変更します。

そして、コアモジュールにもユーザーサービスを追加します。

ユーザーと投稿したコメントを紐付ける

では、チャットコンポーネントを編集していきます。

モックデータをコメントアウトします。

そして次のコードをngOnit()に追加します。

this.afAuth.auth.currentUser:現在ログインしているユーザーを取得します。ユーザーがログインしていない場合、currentUser は null です。

nullの場合は、onAuthStateChangedでログインステータスを監視し、ログインになればユーザーをカレントユーザーとして定義します。

次にユーザークラスの型を変更します。

そして、currentUserの定義をUserとして、変更に伴いテンプレートのパイプも変更していきます。

コメントクラスの型も一箇所変更になります。

これで、チャットと登録した名前が紐づくことになりました。

紐づく以前に作成したデータベースは不要になるので消しましょう。

それでは、だんだんチャットらしくなってきましたが、もう少し機能を実装させる必要があります。

アクセス制限

普通のウェブサービスはログインしたらサインアップのページは開かないようになっています。

このアプリでも同じようにしてみましょう。

AngularのGuardという機能を使って実装させます。

Guardとは?

これはページの遷移を制限する機能です。

  • CanActivate ⇛ ページ遷移可能か
  • CanActivateChild ⇛ 子ルートへの遷移が可能か
  • CanDeactivate ⇛ 現在のコンポーネントから他に遷移可能か
  • CanLoad ⇛ モジュールが読み込み可能か

これらを使ってアクセス制限を作っていきます。

Guardでアクセス制御

次のコマンドを実行します。

コマンド ng g guard auth

このファイルで先程の、CanActivateなどを指定します。

そのまえに、アクセス制御するルーティング設定にGuardを追加していきます。

ルーティングモジュールのサインアップとログインに次のコードを加えます。

canActivate: [ AuthGuard ]

インポートは次のコードです。

import { AuthGuard } from ‘./auth.guard’;

そして、@NgModuleにもAuthGuardを追加します。

providers: [AuthGuard]

これでルーティング設定でAuthGuardを有効にできました。

では、AuthGuardの中身を見ていきましょう。

Guardは基本的に真偽値を返します。

trueが変えると遷移可能で、falseが返ると遷移不可になります。

ここではreturnを条件に依って真偽を返すように書き換えていきます。

afAuth.authState:ログインステータスを取得し、ログインしてなくてuserがNullならtrueを返し、遷移可能にします。

これでログイン中は、ログイン画面やサインアップ画面に遷移できなくなりました。

ログインでチャットを表示

さて、次はログイン状態でのみチャットを表示させるようにしてみましょう。

まず、chat.component.htmlを開き、最初の要素の中にカレントユーザーでない場合は表示させなくします。

次のコードで実装できます。

*ngIf=”currentUser”

これでログインしないとチャットが表示されなくなりました。

では、新規ユーザー向けのトップページを作りましょう。

教材からテンプレートとスタイルシートをコピペします。

chat.component.html(上に追加)

chat.component.css(上に追加)

これでトップページが完成しました。

タイムラインモジュール

チャットに参加しているユーザーリストを表示させてみたいと思います。

次のコマンドを実行します。

コマンド ng g module timeline

作成したtimelineフォルダの中にchatフォルダを移動させます。VSC上でおこないます。

警告が出ますが構わず続けます。

できたらまず、アップモジュールにタイムラインモジュールを追加します。

チャットモジュールは不要になったので消します。

タイムラインモジュールは次のように書きえます。

そして、次のコマンドを実行します。

コマンド ng g module timeline/timeline-routing –flat –module=timeline

ここでは、次のルーティングを設定します。

{ path: ”, component: ChatComponent }

#UsersModuleをルーティング設定したときと同じ要領でアップルーティングモジュールを書き換えます。

これでチャット機能をタイムラインに移すことができました。

では、画面左側にユーザーリストを表示させてみましょう。

まず、次のコマンドを実行します。

コマンド ng g component timeline/user-list

教材からテンプレートとスタイルシートをコピペします。

user-list.component.html

user-list.component.css

そして今作ったテンプレートをアップコンポーネントテンプレートのトップページ以外の先頭に追加します。

<app-user-list>を使って追加できます。

そして、<ng-container *ngIf=”currentUser”>を<app-user-list>の上でくくって、ログインした状態で表示するようにします。

そしてチャットコンポーネントのスタイルシートの.pageを変えます。

さらに、.chat-editorのwidthを次のように書き換えます。

width: calc(75% – 2px);

さて、ではユーザーのリストを取得するようにuser-list.componentを編集していきます。

Firebaseをはじめて触った時のコードと同じです。

  1. コンストラクターでデータベースの中でデータリストが存在する場所を指定します。
  2. その場所のsnapshotChanges()をsubscribeします。
  3. 変化があればユーザー配列にユーザーネームだけをリスト配列から格納します。

その格納されたリストがユーザーネームリストになります。

このリストがテンプレート内の*ngForによって表示されます。

では、このユーザーリストからユーザー詳細ページに飛べるようにしていきます。

ユーザー詳細ページ

ではコンポーネントを作っていきましょう。

コマンド ng g component users/user-detail

教材からテンプレートとスタイルシートをコピペします。

user-detail.component.html

user-detail.component.css

次に、ルーティング設定をおこないます。

ユーザーズルーティングモジュールを開き、次のパスを追加します。

{ path: ‘:id’, component: UserDetailComponent },

インポートも忘れずに。

また、今はuser.uidを作っていないのでuser.uidはNULLでしか返ってきません。

そこでuser.service.tsのcreate()のthen内に次のコードを加えます。

this.db.object(`/users/${user.uid}`).set(new User(user));

これでusers配列内にuidを格納する場所を作ることができました。

setはあれば上書き、なければ新規作成します。

uidを取得できるようになったので<a [routerLink]=”[‘users’, user.uid]”>このタグに依ってユーザー詳細ページのリンクが生成させるようになりました。

詳細ページはhttp://localhost:4200/users/の後にuidが続きます。

user-detail.componentではそのuidをthis.route.snapshot.paramMap.get(‘id’)で取得しています。

そしてそのuidに対応したユーザー情報に変更があればsubscribeして、新しいユーザー情報が詳細ページにも反映されます。

さて、これでチャットとしての機能を実装することができました。

では最後にこのアプリを公開する方法を紹介します。

アプリを公開する

Firebaseホスティングを使って公開してきます。

次のコマンドを実行します。

一旦サーバーを止めてから実行しましょう。

これはFirebaseのプロジェクトを初期化するためのコマンドです。

コマンド firebase init

Are you ready to proceed? (Y/n) が表示されるので y を押して 実行します。

実行すると幾つか選択肢が表示されるので矢印キーで、

>( ) Hosting: Configure and deploy Firebase Hosting sites を選択してスペースを押してから実行します。

次にこのAngularで使っているFirebaseのプロジェクトを選択して実行します。

次に、ディレクトリの名前を入力します。 ⇛ dist と入力します。

これでコンパイルが完了しました。

.firebasercとfirebase.jsonが生成されました。

次にビルドしていきます。

その前に、environmentにあるfirebaseキーをenvironment.prodにも入れましょう。

コマンド ng build –prod

しばらく経てば完了します。

もしもエラーになったら

ERROR in ./node_modules/bootstrap/dist/css/bootstrap.min.css
Module build failed: BrowserslistError: Unknown browser major

こんな風にエラーが出ました・・・

めっちゃ焦りましたが、どうやらbootstrapが古いのが原因のようです。

BrowserslistError: Unknown browser major at error · Issue #9020 · angular/angular-cli

arturovtさんのコメント

“bootstrap”: “^4.0.0-beta.2” the caret here means it will update you to the most recent version, just try yarn upgrade bootstrap@4.0.0-beta.2 or npm update bootstrap@4.0.0-beta.2

まあよくわからんけど、アップデートが必要ということでしてみたけど・・・

またエラー。

どうやらアップデートではなくてインストールで解決するみたいです。

コマンド npm install bootstrap@4.0.0-beta.2

これを実行してからビルドしたらエラーが出ませんでした。

distに圧縮された状態で作成されました。

これをFirebaseのホスティングにデブロイしていきましょう。

コマンド firebase deploy

開くのが次のコマンドです。

コマンド firebase open hosting:site

いちいち打つのが面倒な場合はpackage.jsonファイルに次のコードを入れておくと便利ということです。

“deploy”:ng build –prod && firebase deploy

npm run deployでまとめて実行できます。

さてこれでアプリを公開することができました。

AngularChat

メールアドレスの登録が必要ですが今のところは、自動送信して受信できることを確認しないのでデタラメなアドレスでも登録できます(泣)。

なので好きに遊んでみてください。

シェアする

  • このエントリーをはてなブックマークに追加

フォローする