前回記事「SES営業のぼくでもできた!Google FirebaseでセルフDX(2)」はコチラ

皆さん、こんにちは!
株式会社TSOneでSES営業を担当しているHYです。

弊社が得意としているVue.jsとFireBaseを利用したアプリ開発を素人がどこまでできるのか?
奮闘と現在までの軌跡をご紹介できたらと思います。

Vueプロジェクトの作成、Firebaseプロジェクトの作成と
環境構築を乗り越え、いよいよ開発をスタートしたいと思います。

改めて、何を開発したいかというと
SES営業と、現場常駐エンジニアとの情報共有ができるアプリ。
名付けて営業推進ツール。
エンジニアがお客様先で仕入れたお仕事情報を、営業と共有できるアプリを開発していきます!

と、その前に。またしてもインストールが必要なものがありました。
実際は途中途中で足りないことに気が付いてインストールしていたのですが、
事前に以下のインストール手順を紹介したいと思います。

  • Vuetify
  • Vue Router
  • Vuex
    勝手にvue開発三種の神器と名付けさせていただきました。
Vuetify

Vuetifyを利用することで、画面を作成(描画)するうえで様々な便利タグ(機能)が利用できるようになります。
あと、vue.jsでは一般的なhtmlタグはほぼ使用せず、v- から始まるタグを使用するのが基本となるそうです。

vuetifyのページ↓
https://vuetifyjs.com/ja/introduction/why-vuetify/

コマンドはいつものVScodeのターミナルから今回開発するVueプロジェクトのフォルダ配下で以下を実行するだけです。$ vue add vuetify
vuetifyはnpmは使わないのなんでだろう??

VueRouter

画面の表示や、遷移を制御します。
Vue.jsでは基本的にはApp.vueという1枚の画面の中で
紙芝居のように開発した画面の表示を切り替えているのですが、その切り替えを行ってくれるのがこのVue Router。

コマンドはいつものVscodeのターミナルから今回開発するVueプロジェクトのフォルダ配下で以下を実行です。
$ npm install vue-router

Vue Routerはインストールしただけでは、使用できません。
画面を呼び出すパスと、指定されたパスに紐付く画面を定義するファイルを作成する必要があります。

プロジェクト名 /src の下に router というフォルダを作成し、以下の内容のファイルを作成して配置します。
※すでにインストール処理によって作成されている可能性もあります。
ファイル名はなんでも良さそうでしたが、最初に調べたときのネット情報が index.js だったのでこのファイル名にしています。

# プロジェクト名 /src/router/index.js
import Vue from 'vue'
import VueRouter from "vue-router"

Vue.use(VueRouter)

一旦内容はここまで。
このファイルは後々表示したい画面が追加される度に設定を追加する必要があります。

Vuex

vue.jsの為のデータ保存ツールです。
データベースに保存するのではなく、一時的に情報を保存できる領域を提供してくれます。
A画面で入力→B画面で入力した内容を確認→C画面でDBに格納。という遷移があったときに、
A画面で入力した内容をC画面まで一時的にstoreという領域に保存することができます。
B画面からA画面に戻ったときも、storeに保存していた内容でA画面を復元することもできます。

コマンドはいつものVscodeのターミナルから今回開発するVueプロジェクトのフォルダ配下で以下を実行です。

$npm install vuex – save

vuexもVue Routerと同様に保存したいデータを定義するファイルが必要となります。
最初に調べたときのネット情報が srcの直下にstore.js だったので同じにしてます。

# プロジェクト名/src/store.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

一旦内容はここまで。
このファイルは後々一時的に保存したい情報が追加される度に設定を追加する必要があります。

main.jsの確認

最後に、この三種の神器をインストールしたことを main.js というvueプロジェクトの全てを司る?ファイルに定義してあるか確認します。
↓の記載のように三種の神器がimportで宣言され、且つ new Vueの()括弧内に記載されていればOKです。
記載されていなければ↓のようにしてください。

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import vuetify from './plugins/vuetify'
import store from './store'

Vue.config.productionTip = false

new Vue({
router,
store,
vuetify,
render: h => h(App)
}).$mount('#app')

三種の神器を手に入れたらいよいよです。
冒頭でお話したアプリ開発。
「エンジニアがお客様先で仕入れたお仕事情報を手軽に登録できる機能(画面)」の開発にとりかかりたいと思います!

情報を登録する画面ということで、
開発する内容として必要な要素を考えた結果、以下3ステップが今回の目標です。

  • 登録したい内容を画面から入力できる
  • 入力がされているかチェックする
  • 入力した内容をデータベースに保存する
➀登録したい内容を画面から入力できる

素人にとって肝心なこと、そもそも開発したファイルはどこに作って置けば良いの?
VSCodeでVueプロジェクトのフォルダ構成をみてみると、
恐らく以下のようになっています。

プロジェクト名

- node-modules無視
- public後々重要だけど今は無視
- assetsアイコンとか画像とか使うときにjpegとかimgを配置するフォルダ、今は無視
- components とりあえずなんでもおけるフォルダ
- views共通して利用できる画面を置くフォルダ
- router前述で作成したvue routerのフォルダ
- plugins前述でインストールしたvuetifyの設定ファイルが置かれているフォルダ
- App.vue画面の親分
- main.jsいろんなツール(プラグイン)を利用する宣言する大親分
- firebase.jsonFirebaseに関わる設定を保持するファイル。基本このファイルは無視
- package.json↑と一緒
- store.js前述で作成したvuexで使用するファイル

いろいろありますが、今回はcomponentsフォルダに開発したファイルを置いていくことにしました。
ということでまずは登録画面をcomponentsフォルダに作成していきたいと思います。
ファイル名も単純ですが、Entry.vueという名前にしました。

過去の投稿でも記載しましたが、
vue.jsの特徴として、開発するファイルには、画面の描画を制御するtemplate>タグと
処理を制御する<script>タグがあります。
まずは画面描画が必要なので、<templete>タグの開発をしていきます。

Entry.vueは登録画面なので、入力項目が必要です。
早速、vuetifyで文字を入力できる機能(タグ)を探してみると、
<v-text-field>というのがどうやら入力項目のようです。

ここで弊社TSOneの研究開発部メンバーからいただいたアドバイス。
↓の書き方で画面の内容がイイ感じになるそうです。

<template>
  <v-container class="fill-height d-flex align-center" fluid>
    <v-row justify="center" no-gutters>
      <v-col>
        <! – この中に書きたい事 -->
      </v-col>
    </v-row>
  </v-container>
</template>

では入力項目を3つ表示した画面を作ってみます。

# src/components/Entry.vue
<template>
  <v-container class="fill-height d-flex align-center" fluid>
    <v-row justify="center" no-gutters>
      <v-col>

        <v-text-field
          v-model="item1"
          label="入力項目1"
        ></v-text-field>
        <v-text-field
          v-model="item2"
          label="入力項目2"
        ></v-text-field>
        <v-text-field
          v-model="item3"
          label="入力項目3"
        ></v-text-field>

      </v-col>
    </v-row>
  </v-container>
</template>
<script>
</script>

画面表示するために、開発したEntry.vue をVue Routerに定義する必要があります。

  1. import文で今回作ったEntry.vueを利用することを宣言
  2. importで定義したEnrty.vueを画面制御の対象として定義(path,name,component)
     この定義をすることで、ブラウザから入力するURL(path)に/Entryを指定するとEntry.vueが実行されます。
  3. modeをhistoryモードに設定
     何もしないとhashモードという設定になります。
     環境や好みによるそうですが、今回はhistoryモードにしています。
# src/router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Entry from '@/components/Entry.vue'

Vue.use(VueRouter)
const routes = [
  {
    path: '/Entry',
    name: 'Entry',
    component: Entry
  },
]

const router = new VueRouter({
  mode:'history',
  routes
})
export default router
# App.vue
<template>
  <div id="App">
    <v-app>
      <v-main>
        <router-view />
      </v-main>      
    </v-app>
  </div>
</template>
<script>
export default {
  name: "App",
};
</script>

プログラム側でここまで準備できたらVueプロジェクト(=アプリ)を起動します。
コマンドはいつものVscodeのターミナルから以下を実行。

$vue ui

勝手にブラウザが立ち上がり
作成したプロジェクトのメニュー(プロジェクト ダッシュボード)画面が表示されます。

[タスク]-[serve]-[タスクの実行]のボタンを押してサーバの起動を行います。

正常にサーバーが起動されたら
ブラウザで

http://localhost:8080/Entry

を入力すると、

入力項目の3つある画面が表示されました。
始めての画面表示。うれしい!

①入力がされているかチェックする

画面が表示され、入力項目もできたので、
簡単な必須入力チェックを実装してみます。

# src/components/Entry.vue(抜粋)
        <v-text-field
          v-model="item1"
          label="入力項目1"
          :rules="[required]"
        ></v-text-field>

必須入力チェックをしたい項目に :rules=”[required]” という定義を追加

<script>タグ内にdata()関数を作成し、必須入力チェックを実装
今回は何も考えず、この1文を入れればチェックが実装されます。

<script>
export default {
  name: "Entry",
  data() {
    return {
      required: (value) => !!value || "入力必須項目です。",
    };
  },
};
</script>
③入力した内容をデータベースに保存する

いよいよ画面から入力した情報をデータベースに登録です。
まずはFireStoreDBと接続する為のの設定ファイルの作成が必要のようです。

場所は以下のようにfirebaseというフォルダと、その中にfirestore.jsというファイルを作成しました。
注意:今回はFirebase v8での定義となっています。V9以降はimportの記述など多少変更あります。

# src/firebase/firestore.js
import firebase from 'firebase' 

const firebaseConfig = {
    apiKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    authDomain: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    databaseURL: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    projectId: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    storageBucket: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    messagingSenderId:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 
    appId: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  };

  const settings = { timestampsInSnapshots: true };
  firebase.initializeApp(firebaseConfig);
  firebase.firestore().settings(settings);
  export const db = firebase.firestore();
export default firebase

apiKey~appIdまでの設定は、Firebaseでのアプリ登録時にfirebaseconfigで表示された内容となりますので、
その値で設定します。

以下のサイトからFirebaseを「使ってみる」をクリックし、Googleアカウントを使用してログインします。
https://firebase.google.com/?hl=ja

※すでにログイン済みの場合は、ログイン画面が表示されない場合があります。

表示された画面の[最近のプロジェクト]というカテゴリ上に
今回の手順で作成したFirebaseプロジェクトがあるので、それをクリックするとプロジェクトのメニュー画面が表示されます。

左上の歯車のようなアイコンを選択し-[プロジェクトの設定] をクリックするとFirebaseのプロジェクトの設定が確認できます。

設定ファイルの作成が終わったので、次に画面側の開発をしていきます。

まずはボタンを押したら登録をしたいので、<templete>領域にボタンを作成します。<v-btn> というタグでボタンを用意します。

<v-btn large color="indigo darken-4" dark @click="entry"> 登録 </v-btn>

要素として、large color dark でボタンの見栄えを設定しています。こちらはお好みで。
@click= でボタンがクリックされた際に実行されるmethodを定義します。今回は entry メソッドが実行されます。

ボタンを作成したら<script>領域で処理を記述します。
注意:今回はFirebase v8を利用前提としています。

<script>
import firebase from "@/firebase/firestore";   ①

export default {
  data() {
    return {
      item1: "",                 ②
      item2: "",
      item3: "",
      required: (value) => !!value || "入力必須項目です。",
    };
  },
  methods: {
    async entry() {   ③
      // データ登録用の"EntryInfo"という名前のコレクションへの参照を作成
      const db_EntryInfo = firebase.firestore().collection("EntryInfo");  ④
      // 保存用JSONデータを作成
      const saveData = {
        db_item1: this.item1,
        db_item2: this.item2,
        db_item3: this.item3,
      };
      // addの引数に保存したいデータ(saveData)を渡す
      await db_EntryInfo        ⑤
        .add(saveData)
        .then(function (docRef) {
          // 正常にデータ保存できた時の処理
          alert("登録に成功しました")
        })
        .catch(function (error) {
          // エラー発生時の処理
         alert("登録に失敗しました")
        });
    },
  },
};
</script>
①import firebase from “@/firebase/firestore”;

まず初めに先ほど作成したfirestore.jsの設定を読みこむ宣言します。

②アイテムの定義
      item1: "",
      item2: "",
      item3: "",

入力項目を定義することで<templete>領域と<script>領域の双方で
項目を参照・更新(バインド)できるようにします。

③ async entry() {

ボタンが押された際に実行されるメソッド:entryの定義をします。
このメソッドは少々特殊で async という設定がメソッド名の前についています。
これはこの後の処理ででてくる wait という設定と対になっています。

④ const db_EntryInfo = firebase.firestore().collection(“EntryInfo”);

FirestoreDB上の”EntryInfo”というコレクションへの参照を定義。
コレクション=テーブル と思っていただいて大丈夫だと思います。
※今回 db_EntryInfoという名前にしましたが変数なので特にどんな名前でも問題ないです。

⑤await db_EntryInfo.add(saveData)

add()関数を実行してFirestoreDBへの登録(Insert)を実行します。
EntryInfoというテーブルが存在しなければ作成し、関数の引数で指定のデータを登録します。

ここでawaitという宣言がでてきます。
先ほどメソッドの定義する際のasyncと対になっています。
JavaScriptは非同期処理といって、処理(関数)がどんどん順番に実行されていきます。
その為、先に実行した処理➀で得た結果をもとに、次の処理➁を実行したい場合にawaitを使用します。
await を定義することによって、(あたかも)その定義された処理が完了した後に、次の処理が実行されたようにできます。
※実際にはPromiseという非同期処理の状態を持つオブジェクトを駆使しているようです。

add()関数に渡しているsaveDataについて

      const saveData = {
        db_item1: this.item1,
        db_item2: this.item2,
        db_item3: this.item3,
      };

JSON形式で保存データを定義しています。
:(コロン)を挟んで左側のキーがカラム名
右側の値がそのまま値となります。

ここまでできたら、ブラウザで「http://localhost:8080/Entry」を入力すると、

入力項目が3つ、ボタンが1つある画面が表示されます。

入力項目に適当な値を入力して、ボタンをクリックします。
登録に成功しました。というメッセージがでれば完了です。

画面操作上は正常に終了しました。
実施にFirestoreDBにデータが保存されているか確認しましょう。

ブラウザからFirebaseプロジェクトのページを開きます。
左のメニュー[構築]-[Firestore Database]を選択すると今回登録した
コレクション(テーブル)とデータが表示されています!

ここまでで登録画面を作る基礎ができたので、
今回の本題である「営業推進ツール」。エンジニアが入力する項目を定義した画面を作成してみます。
作業内容や作業場所、作業期間、必要なスキルや条件を登録できる項目を作成します。

今回使用したタグは以下となります。

  • <v-text-field> 簡単な入力内容の場合に使用
  • <v-textarea>  入力したい内容が多い場合の項目に使用
  • <v-date-picker>  作業期間項目のように日付の入力をカレンダーから選択できるする項目に使用

前述したVuetifyのページでは、
いろいろなタグの使用方法がサンプル付きで掲載されています。
使いたい項目はだいたいここを探せばみつかるので是非参考にしてください。vuetifyのページ

追加で、せっかくなのでヘッダーにタイトルロゴを表示させてみました。
ヘッダーに関係する\<v-app-bar>タグの記載のみを以下に抜粋します。

# src/App.vue 
 <v-app-bar app color="indigo darken-4" dense dark height="70">
        <v-card-title >
          <v-img src="@/assets/xxxxxxx.png"></v-img>
        </v-card-title>
 </v-app-bar>

<v-img>タグで表示したいロゴを指定しています。
このサンプルではassetsフォルダ内に配置したpngファイルを参照しています。ファイル名は任意。ロゴの画像データはちょっと苦労しましたがcanvaというツールで作成しました。

それっぽい画面ができました!!
次回は登録した内容を一覧で表示する画面をつくっていきます。