Firebase Firestoreを利用したユーザー認証のあるチャットアプリを実装する(2/2)

前回作った、チャットアプリにユーザー認証を追加していきます。

Firebase Firestoreを利用したユーザー認証のあるチャットアプリを実装する(1/2)
最近、firebaseのデータベースサービスであるfirestoreを利用してサービスを作っています。簡単なfirestoreの操作がわかってきたので、アプリをサンプルにメモします。 Firestoreを使用するにあたって Fi...

 

index.htmlの編集

index.htmlにlogin、logoutボタンの追加とfirebase-authのCDNを読み込みを実装していきます。

<!DOCTYPE html>
<html lang="ja">
<head>
 <meta charset="utf-8">
 <title>ChatApp for firebase</title>
</head>
<body>
<header style="display: flex;">
    <div>ChatApp for firebase</div>
    <div>
        <button id="login">Login</button>
        <button id="logout" class="hidden">Logout</button>
    </div>
</header>
<div style="padding-top: 20px;">
<!-- formの候補をなくすために、autocomplete="off"を追加 -->
<form autocomplete="off">
   <input type="text" id="message" placeholder="Message..">
   <input type="submit" name="" value="firestoreへ">
</form>
<ul id="messages"></ul>
</div>


   <!-- CDNで使いたいfirebaseのサービスを指定 -->
   <script src="https://www.gstatic.com/firebasejs/5.0.4/firebase-app.js"></script>
  <script src="https://www.gstatic.com/firebasejs/5.0.4/firebase-firestore.js"></script>
  <script src="https://www.gstatic.com/firebasejs/5.0.4/firebase-storage.js"></script>
  <script src="https://www.gstatic.com/firebasejs/5.0.4/firebase-auth.js"></script>
  <script src="js/test.js"></script>
</body>
</html>

 

ここから、js/main.jsを編集していきます。

 

インスタンスを追加

// loginインスタンスを定義
const login = document.getElementById('login');

// logoutインスタンスを定義
const logout = document.getElementById('logout');

// authインスタンスを定義(使用可能に)
const auth = firebase.auth();
let me = null;

 

 

ログイン、ログアウトのclickイベントを追加

// loginのclickイベント
login.addEventListener('click', () => {
// login完了
auth.signInAnonymously();
});

// logoutのclickイベント
logout.addEventListener('click', () => {
auth.signOut();
});

 

 

firestoreからデータを取得する処理の変更

onAuthStateChangedでlogin、logoutの変化でイベントを発生させる。

auth.onAuthStateChanged(user => {
if(user) {
me = user;

// login時に重複を防ぐ
while (messages.firstChild) {
       messages.removeChild(messages.firstChild);
   }

// firestoreからcreated順に取得(onSnapshot他のユーザーからの変更を監視)
collection.orderBy('created').onSnapshot(snapshot => {
// 帰ってきたデータをdocとして
snapshot.docChanges().forEach(change => {
if (change.type === 'added') {
     const li = document.createElement('li');
     const data = change.doc.data();
     // 8文字までパスワードを追加
     li.textContent = data.uid.substr(0, 8) + ': ' + data.message;
     messages.appendChild(li);
   }
});

},// logoutすると書き込み権限がなくなるのでerror起こる
error => {});
console.log(`Logged in as: ${user.uid}`);
// loginボタンを隠す
login.classList.add('hidden');
[logout, form, messages].forEach(el => {
      el.classList.remove('hidden');
   });
   return;
}
me = null;
console.log('Nobody logged in');
[logout, form, messages].forEach(el => {
      el.classList.add('hidden');
});
return;
});

 

 

submit時firestoreへ保存する処理の変更

カラムにuser.uidを追加し、画面表示の制御処理を追加していきます。

// submit時のfunction
form.addEventListener('submit', e => {
// ページ遷移をなくす
e.preventDefault();

const val = message.value;
// 空のmessage.valueの投稿を防止する
if (val === "") {
return;
}

/*// firestoreにaddする前にmessage.valueをli化する
const li = document.createElement('li');
   li.textContent = message.value;
   messages.appendChild(li);*/

   // valueリセットする
     message.value = '';

// messagesコレクションに追加
collection.add({
message: val,

// timestampをカラムに追加
created: firebase.firestore.FieldValue.serverTimestamp(),
// userid
uid: me ? me.uid : 'nobody'
})
// 追加に成功した時の処理(docを引数にとる)
.then(doc => {
console.log(`${doc.id}というdocumentsで保存されました!`);
})
// エラー時の処理
.catch(error => {
console.log('document add error!');
console.log(error);
});
});

 

 

最終的なjs/main.jsのソースコード

(() => {
 'use strict';

 const config = {
   apiKey: "",
   authDomain: "",
   databaseURL: "",
   projectId: "",
   storageBucket: "",
   messagingSenderId: ""
 };
 firebase.initializeApp(config);

 const db = firebase.firestore();
 db.settings({
   timestampsInSnapshots: true
 });
 const collection = db.collection('messages');

 const auth = firebase.auth();
 let me = null;

 const message = document.getElementById('message');
 const form = document.querySelector('form');
 const messages = document.getElementById('messages');
 const login = document.getElementById('login');
 const logout = document.getElementById('logout');

 login.addEventListener('click', () => {
   auth.signInAnonymously();
 });

 logout.addEventListener('click', () => {
   auth.signOut();
 });

 auth.onAuthStateChanged(user => {
   if (user) {
     me = user;
     while (messages.firstChild) {
       messages.removeChild(messages.firstChild);
     }

     collection.orderBy('created').onSnapshot(snapshot => {
       snapshot.docChanges().forEach(change => {
         if (change.type === 'added') {
           const li = document.createElement('li');
           const d = change.doc.data();
           li.textContent = d.uid.substr(0, 8) + ': ' + d.message;
           messages.appendChild(li);
         }
       });
     }, error => {});
     console.log(`Logged in as: ${user.uid}`);
     login.classList.add('hidden');
     [logout, form, messages].forEach(el => {
       el.classList.remove('hidden');
     });
     return;
   }
   me = null;
   console.log('Nobody is logged in');
   login.classList.remove('hidden');
   [logout, form, messages].forEach(el => {
     el.classList.add('hidden');
   });
 });


 form.addEventListener('submit', e => {
   e.preventDefault();

   const val = message.value.trim();
   if (val === "") {
     return;
   }

   message.value = '';   

   collection.add({
     message: val,
     created: firebase.firestore.FieldValue.serverTimestamp(),
     uid: me ? me.uid : 'nobody'
   })
   .then(doc => {
     console.log(`${doc.id} added!`);
   })
   .catch(error => {
     console.log('document add error!');
     console.log(error);
   });
 });
})();

 

ファイルをブラウザで確認して動作確認を行ってください。