プログラミング素人のはてなブログ

プログラミングも電気回路も専門外の技術屋の末端が勉強したことや作品をアウトプットするブログ。コードに間違いなど見つけられたら、気軽にコメントください。 C#、Python3、ラズパイなど。

サーバーレス(Firebase)で夫婦で共有できる買い物リストを作った

うちは共働きなので、買い物は帰りが早いほうが買い出しをすることが多いですが、例えば洗面所周りは、モノの消費を妻のほうが把握していることが多いのでこれらを共有する仕組みを作りたかった、というところから始まりました。

Firebaseなら無料で作れそうなので、FirebaseとJavaScriptを合わせて勉強しながら作ってみました。

完成イメージ。

f:id:s51517765:20190715115257j:plain
完成イメージ

要件定義

・夫婦で共有できること。
・無料で使えること。
Androidでもiphoneでも使えること。
・入手済みのものを保存できること。

上の3つはFirebaseを使う時点で成立します。
4つ目は「欲しいものリスト」と「入手済みリスト」を作ることで実現しました。

html

htmlの本文はタイトル、入力ボックス、ボタンなどとリストulです。リストは名前を付けるために、 form name="form1”で囲みます。

<body>
    <h1>買い物リスト</h1>
    <div>
        <p>
            <div><input type="text" name="" id="message" placeholder="品物を入力して追加"></div>
            <div><input type="button" value="追加" id="btnUpload" onclick="addData()"></div>
        </p>
        <div><input type="button" value="再読み込み" id="btnReload" onclick="ListLoad()"></div>
    </div>
    <h3>欲しいものリスト</h3>
    <form name="form1">
        <ul id="List1"></ul>
    </form>
    <div><input type="button" value="入手完了" id="btnDone" onclick="done()"></div>
    <h3>入手済みリスト</h3>
    <form name="form2">
        <ul id="List2"></ul>
    </form>
    <div><input type="button" value="削除" id="btnDelete" onclick="deleteItem()"></div>
</body>

css

簡単にスタイルシートをコピペで作成。最低限の文字の大きさの指定だけです。

/* css checkbox01 */
input[type=checkbox] {
    width: 20px;
    height: 20px;
    vertical-align: middle;
}

input[type="text"] {
    width: 300px;
    height: 20px;
}

html {
    font-size: 20px;
}

h1 {
    font-size: 40px;
}

h2 {
    font-size: 20px;
}

このほかに、htmlのheadには、文字コードスマホ表示用の設定とcssの読み込みを設定します。

    <meta http-equiv="content-type" charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1"><!-- スマホ用の表示拡大 -->
    <link rel="stylesheet" type="text/css" href="css.css">

JavaScript

Firebaseの初期化は管理画面のSettingをコピーします。

<script src="https://www.gstatic.com/firebasejs/5.8.6/firebase.js"></script>
<script>
    // Your web app's Firebase configuration
        var firebaseConfig = {
            apiKey: "*************",
            authDomain: "*************",
            databaseURL: "*************",
            projectId: "*************",
            storageBucket: "",
            messagingSenderId: "*************",
            appId: "*************"
        };
    // Initialize Firebase
firebase.initializeApp(firebaseConfig);

これ以降、要素を追加、要素を削除、画面に表示されるリストの更新、などの関数を作成します。
初めてJavaScriptを触って、はまったところを少し解説します。

JavaScriptは基本文法をQiitaで流れてきた↓でざっと学習したうえで取り組んでいます。
ja.javascript.info

欲しいものリストに追加するときにすでに登録されているモノとの重複を確認するのに、「ローカルに保持した配列をループで確認して一致するものを探す」という方法を使いました。JavaScriptではobj in subjectのようなメソッドがないらしいです。本当か?
要素と一致するものがあるかどうかは、インデックスが0以上になるかどうかで確認します。

 if (subject.indexOf(message) >= 0) {  //if (obj in subject)のようなメソッドが無い
        alert("重複しています。")
  }

リストの中でチェックボックスの状態を確認するには、formで範囲を決めてあげてelements[i]で確認します。
ここで、iをチェックボックスの数を数えて範囲指定をしようとしたら、要素数1のときになぜかundefinedとなってうまくいかなかないという問題がありました。
チェックボックス(リストの要素)の数を別にカウントitemCountとして持たせることで解決しました。

  // i番目のチェックボックスがチェックされているかを判定
  if (document.form1.elements[i].checked) {
        let object_done = document.form1.elements[i].value;
 }

サーバー上の要素を削除するには、キーを指定してあげる必要があります。
コーダーからすると、要素の名前?中身と一致するもの、という考え方をしますが、要素が一致するオブジェクトを探してそのキーで指定する必要があります。

var childData = childSnapshot.val().message;
if (childData) {
    database1.child(childSnapshot.key).remove(); // .keyでIDを取得
}

JavaScriptでの日付の取得の仕方は基本ではありますが一応書いておきます。"月" が+1必要です。

var today = new Date(); //日付
let date = today.getMonth() + 1 + "/" + today.getDate()

www.sejuku.net

チェックボックスのついたリストの作成は、一度リストの中を空にしてからサーバー上の要素にforEachでアクセスし、appendします。
pushするときに重複を確認するためにローカルの配列subjectを用意してサーバーにアクセスしなくてもいいようにしてみました。
cb.valueはチェックされた要素を確認するときに使っています。実際に表示される文字はelement.innerHTML で設定します。

function ListLoad() {
      deleteAllElement()

     var list1 = document.getElementById("List1");
      database1.on("value", function (snapshot) {
      snapshot.forEach(function (childSnapshot) {

       var childData = childSnapshot.val();
      var element = document.createElement("li");

      subject.push(childData.message);  //リストの中身を配列に追加し保持、重複確認のため

      //チェックボックスの追加
      var cb = document.createElement("input");//チェックを作成
      cb.type = "checkbox";
      cb.name = "cb"
      cb.value = childData.message;
      element.innerHTML = childData.message;
      cb.textContent = element.innerHTML;
      element.appendChild(cb);
      list1.append(element);
      });
   });

ページ読み込み時の動作はwindow.onloadで指定します。

window.onload = function () {
     ListLoad();
};

まとめ

これで、一通りのFirebaseのリアルタイムデータベースが使えるようになったと思います。
イデア次第でいろいろ出来そうです。
github.com