素のJSでタイマー機能を作ってみた~firebase連携/CRUD理解(未実装)とTSをGulpで使ってみる~

はじめに

いつも勉強する際はWindowsにデフォルトで入っているアラームを使っています。

前々から、その時間ごとにやったことを記録できるようにできたら嬉しいなと思っていたので素のJSの勉強がてら作ってみます。

※リポジトリは先日作成した簡単ツイートアプリとGulpを共有したく同一プロジェクトで生成しているのでしっかり形になったら上げます。

✅ゴール
・タイマーアプリをつくる。

✅環境
Windows/XAMPP/MySQL

✅参考
📚JS本格入門P360

タイマー機能実装

まずはDateオブジェクトを触ってみます。

let date = new Date();
let d = date;
console.log(d); // 2020-06-12T01:17:27.076Z 数型で取得してるぽい
d = date.toLocaleTimeString();
console.log(d); // 10:15:50
d = date.toTimeString();
console.log(d); // 10:15:50 GMT+0900 (GMT+09:00)
d = date.toDateString();
console.log(d); // Fri Jun 12 2020

🙄こういうときTypeScriptが役立ちそうだなと思ったり・・・

参考:Javascriptのタイマー処理 setIntervalとsetTimeout

タイマー機能の実装にはsetInterval/setTimeoutメソッドを使います。

以下違い。

setTimeout(処理, 時間間隔, 引数); // 指定した時間経過後に処理を実行する
setInterval(処理, 時間間隔, 引数); // 指定した時間ごとに処理を実行する

タイマーを停止させる場合、以下を用いる。

clearTimeout(変数)  // setTimeoutで設定したタイマーを取り消す
clearInterval(変数) // setIntervalで設定したタイマーを取り消す

参考:経過時間(秒数)をリアルタイムに表示する方法 

経過時間については上記のサイトが参考になりました。

参考:insertBeforeで要素の前に挿入する

ラップを先頭に追加していくのに参考。

👇色んな技術を駆使してやったもののラップごとの時間を算出する際に負の値が出てしまう感じに。。。

🙄時間の処理がものすごく大変でした・・・

コードもものすごい量に。。。正規表現できれば少しは簡易化できそうですが。。。

負の値が出ないように処理。

以下のようにvalue属性は文字列になるのでNumber()を入れないと160などになってしまうことがわかりました。要注意!!

hidePassSec.value = Number(hidePassSec.value) + 60;//60s

そして正常に動作するようになったと思いきや。。。

何回か押すと負の値が表示されてしまう不具合。。。

その後、10になった瞬間にエラーが起こることに気付きました。

つまり、原因は条件分岐の方も数字にしていなかったからでした。

else if (Number(hidePassSec.value) < Number(referenceSec.value))

🙄数字と文字列の型がごっちゃになるとこういうこと起こるんですね・・・

尚更TypeScriptにしたくなりました。

後程inputタグのメモにIDを付けたくなった際に逆の事象も発生しました。

createMemoElement.id = "memo"+String(wrapCount);

🙄今度は文字型指定。これ本当に気を付けよう。

その後、作成ボタンを付けてこんな感じにconfirmするように実装。

先日作ったツイートのページにconfirmの情報と持って移動するよう実装していきます。

調べたところlocationオブジェクトでいけそう。参考

location.replace("https://chobimusic.com/tweet?")

ただ別タグでいけなかったのでこちらで。

let href = "https://chobimusic.com/tweet?aaaaa" ;
open(href, "_blank");

ところがどっこい。なぜか?の前にスラッシュが入ってしまう。

仕方ないのでaタグで実装しました。

⇒どうやらこれはサーバー側の仕様っぽい。他のドメインのルートディレクトリに置いたら表示できました。

クエリパラメータについて調べた結果。

参考:URLで使用可能な文字、使用できない文字

#を使うとそれ以降は反映されなくなる。

%0aでTwitter同様改行はできました◎

とりあえずこんな感じで一旦完成。

Firebaseを使ってみる①環境構築~デプロイ

Firebase を JavaScript プロジェクトに追加する(公式)

JavaScript でのインストールと設定(公式)

Firebase

①プロジェクトを生成

②アプリを登録

※アプリのニックネームはFirebaseコンソール内のみで使用みたいです。

ここで表示されるFirebase SDKをコピペ(公式ではhtmlファイルに記述できるようになっています)。

③開発ツールのインストール

npm install -g firebase-tools
firebase --version

ログイン

firebase login

初期化

> firebase init
Are you ready to proceed? (Y/n) // Y
Which Firebase CLI features do you want to set up for this folder? // Database,Hosting
Please select an option: Use an existing project
What file should be used for Database Rules? (database.rules.json)
What do you want to use as your public directory? (public)
Configure as a single-page app (rewrite all urls to /index.html)? (y/N) // N

🙄今回はRealtime Database活用で非SPAの仕様なので上記の感じで。

以下のようにファイルが追加で生成されました。

.firebaserc
firebase.json
database.rules.json
📁public
├ 404.html
└index.html

サーバー起動

firebase serve

このタイミングでfirebase-debug.logが生成。index.htmlの内容が表示されました。

今まで作成していたアプリをpublicディレクトリに移動したところ動作確認できました◎

🙄ローカルサーバー機能も付いているのは初めて知りました。感動!!

気になってしまったので物は試しでデプロイも!

firebase deploy

https://javascript-timer.web.app/にアクセス。

できました。めちゃくちゃ簡単!!笑

🙄firebaseのプロジェクト名がそのままurlになるんですね!!

Firebaseを使ってみる②Realtime Databaseを使う

URLでjsonファイルの取得

index.jsに以下を追記

let firebaseConfig = {
~~省略~~
};
firebase.initializeApp(firebaseConfig);
firebase.analytics();

index.htmlのbodyタグ末に以下を追記

<script src="https://www.gstatic.com/firebasejs/7.15.1/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.15.1/firebase-analytics.js"></script>
<script src="index.js"></script>

🙄index.jsを後ろに置くのがポイントです。こうすることでfirebaseオブジェクトを読み込めるようになります。

次にfirebase上で仮のデータを作成。

🙄値を入れるとネストできなくなる

以下の感じで一旦完成とする。

ためしにhttps://javascript-timer.firebaseio.com/result.jsonにアクセス。権限エラー。

ルールを確認すると読み書きがfalseになっていたのでtrueに変更。

再度アクセス。取得できた◎

ただ上記でnullになっているのが気になりますね。。。笑

https://javascript-timer.firebaseio.com/result/1.jsonでネストされた値の取得。

https://javascript-timer.firebaseio.com/.jsonで全体の取得。

🙄シークレットで見るとGoogleのJSONアプリが起動されないので上記のような表示になりますね。

https://javascript-timer.firebaseio.com/result/1/学習したこと.jsonで特定の値を取得。

🙄いい感じですね!!

アプリからデータの取得

index.jsに以下を追記

let db = firebase.database();

するとコンソールに以下のようなエラーが・・・

Uncaught TypeError: firebase.database is not a function

ここを参考にindex.htmlに以下を追記。

<script src="https://www.gstatic.com/firebasejs/7.15.1/firebase-database.js"></script>

🙄この際、取得するファイルのバージョンを統一しないと僕の場合はエラーが出たので注意が必要かもです。

参考:ウェブでのデータの読み取りと書き込み(公式)

データベースでデータの読み書きを行うには、firebase.database.Reference のインスタンスが必要

以下で取得できました。

let db = firebase.database();
let resultDB = db.ref('result');
resultDB.on('value', function(snapshot) {
  var result = snapshot.val();
  console.log(result);
});

valueイベントでパスのコンテンツ全体に対する変更の読み取りとリッスンを行う。

スクリプトは最終的に以下の感じでまとめました。

firebase.database().ref('result').on('value', (snapshot) => {
  let resultDB = snapshot.val();
  console.log(resultDB);
});;

引数に使われているsnapshotはストレージ中に過去のある一時点で存在したファイルとディレクトリの集合、またはその記録処理を実現する仕組みとのこと。

🙄地味にスクリプト長いですね。。。笑

続いて値を使いこなしてみる。

参考:[javascript] 関数の外から関数内の変数を使う

上記を参考に以下のようにコードを修正することで値を関数外から使える。

let resultDB;
firebase.database().ref('result').on('value', (snapshot) => {
  resultDB = snapshot.val();
});;
addEventListener("DOMContentLoaded", () => {
  startBtn.addEventListener('click',() => {
    console.log(resultDB);

※スタートボタンで取得ですが、データの取得までに時間がかかるので取得前に押すとundefinedになります。

🙄徐々にJavaScriptの仕様が理解できて来た気がする。これ非同期でちゃんと処理させないとundefinedなって描画されないですね!

これで取得するとこうなる。

firebase.database().ref('result/1').on('value', (snapshot) => {
  resultDB = snapshot.val();
});;

更に「result/1/学習したこと」で「Docker」を取得できました◎

実際に描画させていく。この際とんでもないことに気付きました。プロパティが日本語。笑

beforeStudyTime.textContent = resultDB.学習したこと;

当然エラーだったので以下の形に変更。

このタイミングでデフォルトだとjavascript-timer(親DBの名前)に値nullが入っていることに気付いたので消しました。

以下のように編集で値が取得されました◎

firebase.database().ref('1').on('value', (snapshot) => {
~~~~
console.log(resultDB);
beforeStudyTime.textContent = resultDB.study1;

ただこれだけだとスタートボタンをページを開いた瞬間に押すと、cannot read propertyになってアプリ自体が動作しなくなってしまう

🙄必然的に非同期処理が必要になりますね。

値の追加

追加は以下で実装できました。ref()メソッドで名前、setメソッドで名前と値入れればOK。とても簡単!!

firebase.database().ref('3').set({
  time: "3時間"
});

※ついでに.setメソッドで異なる値を定義すれば更新もできることがわかりました。

値の削除

removeメソッドを使えばOK

db.ref('3').remove();

余談ですがこれでデバッグしやすくなりました。

db.ref('3').remove(console.log("firebaseDelete"));

別パターンでsetメソッドで値にnullを指定するパターンも◎

db.ref('3').set({
  time: null
});

ちなみに以下を実行してから

db.ref('3').set({
  test:"値には何でも入れられるよ",
  time: "3時間",
  stydy:"JavaScript"
});

これを実行するとtime以外は削除されることがわかりました。

db.ref('3').set({
  time: "4時間",
});

🙄なんとなく仕組みがわかってきました。setは全て1から作り直すイメージですね。

値の更新

上記の仕様からsetメソッドでもできますが、ほかの値を残しつつ一部を編集したい場合はupdateメソッド

db.ref('3').update({
  time: "4時間",
});

FirebaseのCRUDまとめ

取得:on() 参考

追加:set(),push(),update() 参考

※pushは以下のように一意のKeyを生成して追加する。updateも使えるが基本更新で使う。

更新:update(),set() 参考

※setは1から生成で他の値を消してしまうので基本はupdateを使う。

削除:remove() 参考

※setで適当な名前1つとnullで削除、updateですべての名前の値をnullで削除。

👇以前調べた内容に追記しました。

Vue.jsでのfirebaseの設定と教材備忘録

🙄これ調べたのが5月初旬。当時は全く理解できなかったので分かるようになって嬉しい。

TypeScriptをGulpで使ってみる

参考:gulpでtypscriptをコンパイルする

記事自体はちょい古いけど試してみる。

インストール

npm install gulp-typescript typescript -D

公式見ると、TypeScript本体のインストールも必要とのこと。

gulpfile.jsを編集

let  typescript = require('gulp-typescript');

gulp.task('ts', function() {
  return(  
    gulp.src([
      './timer/**/*.ts',
      '!./node_modules/**'//node_modules配下は除外する
    ])
      .pipe(typescript())
      .pipe(gulp.dest('./dist_ts'))
  );
});

timer.tsの作成

let date = new Date();
let d:object = date;
console.log(d); // 2020-06-12T01:17:27.076Z 数型で取得してるぽい
let d1:string = date.toLocaleTimeString();
console.log(d1); // 10:15:50
let d2:string = date.toTimeString();
console.log(d2); // 10:15:50 GMT+0900 (GMT+09:00)
let d3:string = date.toDateString();
console.log(d3); // Fri Jun 12 2020

実行

gulp ts

躓いた点

✅TSコンパイル後、コンパイルで生成されたJSの変数と被ってエラーと表示される。

tsconfig.jsonを作成で解決

tsc --init

✅正規表現、eval関数

おわりに

GulpでTSのコンパイルもできる環境を作ってみて。

自動コンパイルするとなると変数なり使ってまとめて監視してあげる必要があることに気付いた。追って以下のような記事を参考に作っていきたい。

参考:Gulp-typescript + Typescript + Gulp v4 を使ってみました

また、Firebase(Realtime Database)の基本的な仕様は理解できるようになったので嬉しい。

続いてFirebaseを上手く交えた機能実装(非同期処理)をしていきたい。

✅その他参考

なぜhead要素内で外部JavaScriptファイルを読み込むのが良くないのか?

コメントを残す