Vue.js 連絡先追加フォームのfirebase連携

以下でフロントを実装した連絡先フォームをfirebaseと連携する

 

kirikko-scondcube.hatenablog.com

 

firebaseセットアップ

firebaseコンソールからプロジェクトの追加を選択。

f:id:kirikko_Scondcube:20200803020452p:plain

必要事項を選択し、プロジェクトを作成後、webアプリを選択で上記画面が出る。

このスクリプトをコピーしVue cliのpublic/index.htmlのbodyタグのとじタグの上へ貼り付ける。

これでVue.jsでfirebaseを利用する下準備は完了

 

 

firebaseのライブラリの設定

前述でfirebaseの設定をしただけだと読み込みのタイミングでエラーが出ることがある。そのため、Vueに適した内容にfirebaseをセットアップする

 

コンソールで

npm install firebase

 

インストール後、index.htmlの前述で貼り付けたfirebaseのスクリプトを全て切り取り、src/main.jsへ移動する。

移動先はVue.config.productiontTipの下

そしてそのまま移動するとエラー表示が出る(波下線など)。

そこで<script>タグを削除しconfigのみを残す。

そしてデフォルトのvarをconstとし、firebaseをインポートする

 

src/main.js(keyなどの記述は削除しているが配置は以下)

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


Vue.config.productionTip = false



// Your web app's Firebase configuration
const firebaseConfig = {
apiKey: "",
authDomain: "",
databaseURL: "",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: ""
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);



new Vue({
router,

//router:router,と同じ意味上は省略の記載方法
store,

vuetify,
render: h => h(App)
}).$mount('#app')

以上でセットアップ完了

 

Google認証の設定方法

firebase consoleにいく。

プロジェクトを選択

サイドメニューのAuthenticationを選択

sign in methodを選択する。

「無効」となっているGoogleを選択すると以下の画面になる。

f:id:kirikko_Scondcube:20200803023204p:plain

右上のバーを押して無効→有効にするに変更。

プロジェクト名を任意で記述する。

プロジェクトのサポートメールに自身のメールアドレスを入力する。

右下の保存ボタンを押して認証が有効になる。

 

 

firebaseログイン認証の実装

src/store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
import firebase from 'firebase'

Vue.use(Vuex)

export default new Vuex.Store({
state: {
drawer: false,
addresses:

},
mutations: {
toggleSideMenu(state){
state.drawer = !state.drawer
},
addAddress (state, address) {
state.addresses.push(address)
}
},
actions: {
login(){
const google_auth_provider = new firebase.auth.GoogleAuthProvider()
firebase.auth().signInWithRedirect(google_auth_provider)
},
toggleSideMenu({commit}){
commit('toggleSideMenu')
},
addAddress({ commit }, address){
commit('addAddress',address)
}
},
modules: {
}
})

firebase をインポートする

import firebase from 'firebase'

アクションにログイン処理を記入

login(){
const google_auth_provider = new firebase.auth.GoogleAuthProvider()
firebase.auth().signInWithRedirect(google_auth_provider)
},

 

 

views/Home.vue

<template>
<v-container text-xs-center justify-center>
<v-layout row wrap>
<v-flex xs12>
<h1>マイアドレス帳</h1>
<p>マイアドレス帳をご利用の方は、Googleアカウントでログインしてください。</p>
</v-flex>

<v-flex xs12 mt-5>
<v-btn color='info' @click="login">Googleアカウントでログイン</v-btn>
</v-flex>
</v-layout>
</v-container>
</template>

<script>
// @ is an alias to /src @/components以下でファイルを指定すると参照できるようになるよと書いてある。
import{mapActions} from 'vuex'

export default {
methods:{
...mapActions(['login'])
}}
</script>

ログイン用のカードをvitifyから引用

googleアカウントでログインのボタンにクリックイベントを持たせ、押すとloginアクションが実行されるようにする

<v-container text-xs-center justify-center>
<v-layout row wrap>
<v-flex xs12>
<h1>マイアドレス帳</h1>
<p>マイアドレス帳をご利用の方は、Googleアカウントでログインしてください。</p>
</v-flex>

<v-flex xs12 mt-5>
<v-btn color='info' @click="login">Googleアカウントでログイン</v-btn>
</v-flex>
</v-layout>
</v-container>

 

vuexをインポートする

import{mapActions} from 'vuex'

メソッドでstoreのログインアクションを呼び出せるようにする

methods:{
...mapActions(['login'])
}}

 

結果

f:id:kirikko_Scondcube:20200803091726p:plain


ログインボタンを押すとgoogle認証が働く

*この時本来ログイン画面では上のサイドメニューを消したいが消せていない。

原因を追求する必要あり

後に削除する機能を実装するため今は無視して平気

 

ログインユーザー取得機能の実装

 

src/store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
import firebase from 'firebase'

Vue.use(Vuex)

export default new Vuex.Store({
state: {
login_user:null,
drawer: false,
addresses:

},
mutations: {
setLoginUser(state, user){
state.login_user =user
},
toggleSideMenu(state){
state.drawer = !state.drawer
},
addAddress (state, address) {
state.addresses.push(address)
}
},
actions: {
setLoginUser({commit},user){
commit('setLoginUser',user)
},
login(){
const google_auth_provider = new firebase.auth.GoogleAuthProvider()
firebase.auth().signInWithRedirect(google_auth_provider)
},
toggleSideMenu({commit}){
commit('toggleSideMenu')
},
addAddress({ commit }, address){
commit('addAddress',address)
}
},
modules: {
}
})

stateに

login_user:null,
 

を追加

mutationsに

setLoginUser(state, user){
state.login_user =user
},

を追加

actionsに

setLoginUser({commit},user){
commit('setLoginUser',user)
},

 

views/App.vue

<template>
<v-app>
<v-app-bar
app
color="primary"
dark
>
<v-app-bar-nav-icon @click.stop="toggleSideMenu"></v-app-bar-nav-icon>
<v-toolbar-title>マイアドレス帳</v-toolbar-title>
<v-spacer></v-spacer>
</v-app-bar>
<SideNav/>

<v-content>
<SideNav/>
<v-container fluid fill-height align-start>
<router-view/>
</v-container>
</v-content>
</v-app>
</template>
<script>
import firebase from 'firebase'
import {mapActions} from 'vuex'
import SideNav from './components/SideNav'
export default {
name: 'App',
components: {
SideNav
},
created(){
firebase.auth().onAuthStateChanged(user => {
if(user){
this.setLoginUser(user)
}
})
},
data: () => ({
//
}),
methods: {
...mapActions(['toggleSideMenu', 'setLoginUser'])
}
};
</script>

 

firebaseをインポート

import firebase from 'firebase'
 

 

createdの処理を追加

created(){
firebase.auth().onAuthStateChanged(user => {
if(user){
this.setLoginUser(user)
}

 

mapActionsにsetLoginUserを追記

...mapActions(['toggleSideMenu', 'setLoginUser'])
 

 

この記述をするとvueのデベロッパーツールでログイン状態を見れる。

f:id:kirikko_Scondcube:20200803092547p:plain

 

stateのlogin_userが最初はnullだが、ログイン後に見るとobjectが格納される。

 

ログアウト機能の実装

App.vue

<template>
<v-app>
<v-app-bar
app
color="primary"
dark
>
<v-app-bar-nav-icon @click.stop="toggleSideMenu"></v-app-bar-nav-icon>
<v-toolbar-title>マイアドレス帳</v-toolbar-title>
<v-spacer></v-spacer>
<v-toolbar-items>
<v-btn @click='logout'>ログアウト</v-btn>
</v-toolbar-items>
</v-app-bar>
<SideNav/>

<v-content>
<SideNav/>
<v-container fluid fill-height align-start>
<router-view/>
</v-container>
</v-content>
</v-app>
</template>
<script>
import firebase from 'firebase'
import {mapActions} from 'vuex'
import SideNav from './components/SideNav'
export default {
name: 'App',
components: {
SideNav
},
created(){
firebase.auth().onAuthStateChanged(user => {
if(user){
this.setLoginUser(user)
}else
this.deleteLoginUser()
})
},
data: () => ({
//
}),
methods: {
...mapActions(['toggleSideMenu', 'setLoginUser','deleteLoginUser'])
}
};
</script>

 

ログアウトボタンを追加

<v-toolbar-items>
<v-btn @click='logout'>ログアウト</v-btn>
</v-toolbar-items>

 

ログイン状態の変更を管理するためにelse文を追加

}else
this.deleteLoginUser()

 

mapActionsにログアウト機能で使用する「logout, deleteLoginUser」を追加

...mapActions(['toggleSideMenu', 'setLoginUser','deleteLoginUser'])
 

 

store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
import firebase from 'firebase'

Vue.use(Vuex)

export default new Vuex.Store({
state: {
login_user:null,
drawer: false,
addresses:

},
mutations: {
setLoginUser(state, user){
state.login_user =user
},
deleteLoginUser(state, user){
state.login_user = null
},
toggleSideMenu(state){
state.drawer = !state.drawer
},
addAddress (state, address) {
state.addresses.push(address)
}
},
actions: {
setLoginUser({commit},user){
commit('setLoginUser',user)
},
deleteLoginUser({commit}){
commit('deleteLoginUser')
},
logout(){
firebase.auth().signOut()
},
login(){
const google_auth_provider = new firebase.auth.GoogleAuthProvider()
firebase.auth().signInWithRedirect(google_auth_provider)
},
toggleSideMenu({commit}){
commit('toggleSideMenu')
},
addAddress({ commit }, address){
commit('addAddress',address)
}
},
modules: {
}
})

 

store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
import firebase from 'firebase'

Vue.use(Vuex)

export default new Vuex.Store({
state: {
login_user:null,
drawer: false,
addresses:

},
mutations: {
setLoginUser(state, user){
state.login_user =user
},
deleteLoginUser (state) {
state.login_user = null
},
toggleSideMenu(state){
state.drawer = !state.drawer
},
addAddress (state, address) {
state.addresses.push(address)
}
},
actions: {
setLoginUser({commit},user){
commit('setLoginUser',user)
},
logout () {
firebase.auth().signOut()
},
deleteLoginUser ({ commit }) {
commit('deleteLoginUser')
},
login(){
const google_auth_provider = new firebase.auth.GoogleAuthProvider()
firebase.auth().signInWithRedirect(google_auth_provider)
},
toggleSideMenu({commit}){
commit('toggleSideMenu')
},
addAddress({ commit }, address){
commit('addAddress',address)
}
},
modules: {
}
})

 

ミューテーションズにログアウト時にstateの状態をnullに戻す記述を追加

deleteLoginUser (state) {
state.login_user = null
},

 

アクションズにログアウト機能と、ユーザーログイン状態の削除機能を追加

logout () {
firebase.auth().signOut()
},
deleteLoginUser ({ commit }) {
commit('deleteLoginUser')
},

 

ログイン認証後、自分のgoogleのアイコン(img画像)と名前が出るように実装 & ログイン時のみログアウト表示されるようにする

App.vue

<template>
<v-app>
<v-app-bar
app
color="primary"
dark
>
<v-app-bar-nav-icon @click.stop="toggleSideMenu"></v-app-bar-nav-icon>
<v-toolbar-title>マイアドレス帳</v-toolbar-title>
<v-spacer></v-spacer>
<v-toolbar-items v-if="$store.state.login_user">
<v-btn text @click="logout">ログアウト</v-btn>
</v-toolbar-items>
</v-app-bar>
<SideNav/>
<v-content>
<v-container fluid fill-height align-start>
<router-view/>
</v-container>
</v-content>
</v-app>
</template>
<script>
import firebase from 'firebase'
import SideNav from './components/SideNav'
import { mapActions } from 'vuex'
export default {
name: 'App',
components: {
SideNav
},
created () {
firebase.auth().onAuthStateChanged(user => {
if (user) {
this.setLoginUser(user)
} else {
this.deleteLoginUser()
}
})
},
data: () => ({
//
}),
methods: {
...mapActions(['toggleSideMenu', 'setLoginUser', 'logout', 'deleteLoginUser'])
}
};
</script>

 

追加項目

<v-toolbar-items v-if="$store.state.login_user">
<v-btn text @click="logout">ログアウト</v-btn>
</v-toolbar-items>
 

v-toolvarpitemsにv-ifを入れてログイン状態のチェックをすることで、ログインボタンの表示・非表示をしている。

 

store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
import firebase from 'firebase'

Vue.use(Vuex)

export default new Vuex.Store({
state: {
login_user:null,
drawer: false,
addresses: []

},
mutations: {
setLoginUser(state, user){
state.login_user =user
},
deleteLoginUser (state) {
state.login_user = null
},
toggleSideMenu(state){
state.drawer = !state.drawer
},
addAddress (state, address) {
state.addresses.push(address)
}
},
actions: {
setLoginUser({commit},user){
commit('setLoginUser',user)
},
logout () {
firebase.auth().signOut()
},
deleteLoginUser ({ commit }) {
commit('deleteLoginUser')
},
login(){
const google_auth_provider = new firebase.auth.GoogleAuthProvider()
firebase.auth().signInWithRedirect(google_auth_provider)
},
toggleSideMenu({commit}){
commit('toggleSideMenu')
},
addAddress({ commit }, address){
commit('addAddress',address)
}
},
getters: {
userName: state => state.login_user ? state.login_user.displayName : '',
photoURL: state => state.login_user ? state.login_user.photoURL : ''
},
modules: {
}
})

gettersを追加し使用可能にする

getters: {
userName: state => state.login_user ? state.login_user.displayName : '',
photoURL: state => state.login_user ? state.login_user.photoURL : ''
},

 

src/components/SideNav.vue

<template>
<v-navigation-drawer v-model="$store.state.drawer" absolute temporary>
<v-list>
<v-list-item>
<v-list-item-avatar>
<img v-if="photoURL" :src="photoURL">
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title>{{userName}}</v-list-item-title>
</v-list-item-content>
</v-list-item>
<v-divider></v-divider>
<v-list-item v-for="(item, index) in items" :key="index" :to="item.link">
<v-list-item-icon>
<v-icon>{{ item.icon }}</v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title>{{ item.title }}</v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list>
</v-navigation-drawer>
</template>

<script>
import { mapGetters } from 'vuex'
export default {
data () {
return {
items: [
{ title: 'ホーム', icon: 'mdi-home', link: { name: 'home'} },
{ title: '連絡先一覧', icon: 'mdi-menu', link: { name: 'addresses' } }
]
}
},
computed: {
...mapGetters(['userName', 'photoURL'])
}
}
</script>

 

v-list-item-avatarのimgを書き換え

<img v-if="photoURL" :src="photoURL">

 

さらにマスタッシュでuserNameとすることで自身のgoogleアカウント名を表示

<v-list-item-title>{{userName}}</v-list-item-title>
 

 

ゲッターズを使用できるようにインポート

import { mapGetters } from 'vuex'
 

 

ゲッターズの使用は以前から使用しているmapActionsに似ているが、こちらではmethodsではなくcomputedを使用する。

computed: {
...mapGetters(['userName', 'photoURL'])
}
※ここで復習mapActions

store/index.jsでactionsに処理を記載

その処理を〇〇.vueファイルでimport。同一vueファイルのインポートの下にmethodsを定義しindex.jsのactionsを呼び出す

 

ログイン後に連絡先一覧ページに遷移 / ログアウト後にホーム画面に遷移を実装*(未解決あり)*

 

src/App.vue

<!-- <v-app-bar-nav-icon @click.stop="toggleSideMenu"></v-app-bar-nav-icon> -->
<v-app-bar-nav-icon v-show="$store.state.login_user" @click.stop="toggleSideMenu"></v-app-bar-nav-icon>

コメントアウト部分を下の行のようにv-showを追記

v-showでログインしていないときはサイドバーのメニューアイコンを消し、ログインしていると表示するようにしている。

 

以下ではログイン後に連絡先ページへ遷移する記述と、ログアウト時ホーム画面に戻る記述をしている。

*しかし、コメントアウト部分が本来必要なのだが、これを入れるとログインしていないときにログインボタンがホーム画面で表示されないバグがある。

if (user) {
this.setLoginUser(user)
if (this.$router.currentRoute.name === 'home') {
this.$router.push({ name: 'addresses' }, () => {})
}
} else {
this.deleteLoginUser()
// this.$router.push({ name: 'home' }, () => {})
}

 

 

src/comoponents/SideNav.vue

// { title: 'ホーム', icon: 'mdi-home', link: { name: 'home'} },
{ title: '連絡先一覧', icon: 'mdi-menu', link: { name: 'addresses' } }

コメントアウト部分を削除してOKにした。

 

cloud firestoreとの接続

firebaseコンソールへいく。

左側のサイドメニューからdatabaseを選択

新規でデータベースの登録をする

今回はロックモードで登録

登録するとトップ画面にいく

f:id:kirikko_Scondcube:20200803140345p:plain

 

上記画面まで行ったら次に上にあるルールタブを選択。

f:id:kirikko_Scondcube:20200803140622p:plain

この画面で読み書き可能なルールを設定する。

cloud firestoreではパスの指定でデータ保存先を設定可能

 

今回は

各ユーザーの連絡先情報を

/users/{userId}/addresses/{addressId}

の階層に保存する

 

ルールのデフォルト

 
 
 

変更後

rules_version = '2';
  service cloud.firestore {
    match /databases/{database}/documents {
      match /users/{userId}/addresses/{addressId} {
        allow read,update, delete: if request.auth.uid == userId;
        allow create: if request.auth.uid != null;
     }
   }
}

 

match /databases/{database}/documentsが保存先のパス

allowで認証されたユーザーIDが投稿のIDと同じ時に読み取り、更新、削除を許可している。

allow createは認証済みユーザーであれば新規登録を可能にしている。

 

ルールーは以上

 

cloud firestoreに保存する記述をする

store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
import firebase from 'firebase'

Vue.use(Vuex)

export default new Vuex.Store({
state: {
login_user:null,
drawer: false,
addresses:

},
mutations: {
setLoginUser(state, user){
state.login_user =user
},
deleteLoginUser (state) {
state.login_user = null
},
toggleSideMenu(state){
state.drawer = !state.drawer
},
addAddress (state, address) {
state.addresses.push(address)
}
},
actions: {
setLoginUser({commit},user){
commit('setLoginUser',user)
},
logout () {
firebase.auth().signOut()
},
deleteLoginUser ({ commit }) {
commit('deleteLoginUser')
},
login(){
const google_auth_provider = new firebase.auth.GoogleAuthProvider()
firebase.auth().signInWithRedirect(google_auth_provider)
},
toggleSideMenu({commit}){
commit('toggleSideMenu')
},
addAddress({getters, commit }, address){
if(getters.uid)firebase.firestore().collection(`users/${getters.uid}/addresses`).add(address)
commit('addAddress',address)
}
},
getters: {
userName: state => state.login_user ? state.login_user.displayName : '',
photoURL: state => state.login_user ? state.login_user.photoURL : '',
uid: state => state.login_user ? state.login_user.uid:null
},
modules: {
}
})

 

追加点

ゲッターズにuidを定義

uid: state => state.login_user ? state.login_user.uid:null
 

 

actionsのaddAddressの引数にgettersを追加し、if文を追加する。

addAddress({getters, commit }, address){
if(getters.uid)firebase.firestore().collection(`users/${getters.uid}/addresses`).add(address)
commit('addAddress',address)
}

 

そうすると連絡先の追加をするとcloud firestoreのデータベース上に保存される

(この時点では保存はされるが表示はリロードで消える)

f:id:kirikko_Scondcube:20200803143228p:plain

 

このようにデータが登録されていることが確認できる

 

登録したデータの表示

store/index.js

actionsに以下の記述を追加

fetchAddresses({getters, commit}){
firebase.firestore().collection(`users/${getters.uid}/addresses`)
.get().then(snapshot =>{snapshot.forEach(doc => commit('addAddress', doc.data()))
})
},

snapshotにfirebaseに保存したデータがオブジェクトでは入っている。それをforEachで取得している。

 

App.vue

<template>
<v-app>
<v-app-bar
app
color="primary"
dark
>
<!-- <v-app-bar-nav-icon @click.stop="toggleSideMenu"></v-app-bar-nav-icon> -->
<v-app-bar-nav-icon v-show="$store.state.login_user" @click.stop="toggleSideMenu"></v-app-bar-nav-icon>
<v-toolbar-title>マイアドレス帳</v-toolbar-title>
<v-spacer></v-spacer>
<v-toolbar-items v-if="$store.state.login_user">
<v-btn text @click="logout">ログアウト</v-btn>
</v-toolbar-items>
</v-app-bar>
<SideNav/>
<v-content>
<v-container fluid fill-height align-start>
<router-view/>
</v-container>
</v-content>
</v-app>
</template>
<script>
import firebase from 'firebase'
import SideNav from './components/SideNav'
import { mapActions } from 'vuex'
export default {
name: 'App',
components: {
SideNav
},
created () {
firebase.auth().onAuthStateChanged(user => {
if (user) {
this.setLoginUser(user)
this.fetchAddresses()
if (this.$router.currentRoute.name === 'home') {
this.$router.push({ name: 'addresses' }, () => {})
}
} else {
this.deleteLoginUser()
// this.$router.push({ name: 'home' }, () => {})
}
})
},
data: () => ({
//
}),
methods: {
...mapActions(['toggleSideMenu', 'setLoginUser', 'logout', 'deleteLoginUser','fetchAddresses'])
}
};
</script>

 

追加ポイントの説明

mapActionsに以下のコード(fetchAddresses)を追記

...mapActions(['toggleSideMenu', 'setLoginUser', 'logout', 'deleteLoginUser','fetchAddresses'])
 

 

さらにcreatedに以下のコードを追記

created () {
firebase.auth().onAuthStateChanged(user => {
if (user) {
this.setLoginUser(user)
this.fetchAddresses()
if (this.$router.currentRoute.name === 'home') {
this.$router.push({ name: 'addresses' }, () => {})
}
} else {
this.deleteLoginUser()
// this.$router.push({ name: 'home' }, () => {})
}

 

ここでは

this.fetchAddresses()

の一文を追加している。

 

これで登録した内容がリロードしても表示されるようになる

 

編集を可能にする

 

store/index.js

getters部分に

getters: {
userName: state => state.login_user ? state.login_user.displayName : '',
photoURL: state => state.login_user ? state.login_user.photoURL : '',
uid: state => state.login_user ? state.login_user.uid:null,
getAddressById: state => id => state.addresses.find(address => address.id === id)
},
 

以下を追記

getAddressById: state => id => state.addresses.find(address => address.id === id)
 

 

views/AddressForm.vue

<template>
<v-container text-xs-center>
<v-layout row wrap justify-center>
<v-flex xs12 class="text-center">
<h1>連絡先編集</h1>
</v-flex>

<v-flex xs5 mt-5>
<v-card>
<v-card-text>
<v-form>
<v-text-field v-model="address.name" label="名前"></v-text-field>
<v-text-field v-model="address.tel" label="電話番号"></v-text-field>
<v-text-field v-model="address.email" label="メールアドレス"></v-text-field>
<v-text-field v-model="address.address" label="住所"></v-text-field>
<div class="text-center">
<v-btn @click="$router.push({ name: 'addresses' })">キャンセル</v-btn>
<v-btn color="info" class="ml-2" @click="submit">保存</v-btn>
</div>
</v-form>
</v-card-text>
</v-card>
</v-flex>
</v-layout>
</v-container>
</template>

<script>
import { mapActions } from 'vuex'

export default {
created(){
if(!this.$route.params.address_id)return
 
const address = this.$store.getters.getAddressById(this.$route.params.address_id)
if(address){
this.address = address
}else{
this.$router.push({name:'addresses'})
}
},
data () {
return {
address: {}
}
},
methods: {
submit () {
this.addAddress(this.address)
this.$router.push({ name: 'addresses' })
this.address = {}
},
...mapActions(['addAddress'])
}
}
</script>

 

以下createdが追記部分

created(){
if(!this.$route.params.address_id)return
 
const address = this.$store.getters.getAddressById(this.$route.params.address_id)
if(address){
this.address = address
}else{
this.$router.push({name:'addresses'})
}
},

 

これで編集ページにいくと登録データが表示される。

 

更新処理の実装

 

store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
import firebase from 'firebase'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
login_user: null,
drawer: false,
addresses:
},
mutations: {
setLoginUser (state, user) {
state.login_user = user
},
deleteLoginUser (state) {
state.login_user = null
},
toggleSideMenu (state) {
state.drawer = !state.drawer
},
addAddress (state, { id, address }) {
address.id = id
state.addresses.push(address)
},
updateAddress(state, {id, address}){
const index = state.addresses.findIndex(address => address.id === id)
state.addresses[index] = address
}
},
actions: {
setLoginUser ({ commit }, user) {
commit('setLoginUser', user)
},
fetchAddresses ({ getters, commit }) {
firebase.firestore().collection(`users/${getters.uid}/addresses`).get().then(snapshot => {
snapshot.forEach(doc => commit('addAddress', { id: doc.id, address: doc.data() }))
})
},
login () {
const google_auth_provider = new firebase.auth.GoogleAuthProvider()
firebase.auth().signInWithRedirect(google_auth_provider)
},
logout () {
firebase.auth().signOut()
},
deleteLoginUser ({ commit }) {
commit('deleteLoginUser')
},
toggleSideMenu ({ commit }) {
commit('toggleSideMenu')
},
addAddress ({ getters, commit }, address) {
 
if (getters.uid) {
firebase.firestore().collection(`users/${getters.uid}/addresses`).add(address).then(doc => {
commit('addAddress', { id: doc.id, address })
})
}
},
updateAddress({getters, commit},{id, address}){
if(getters.uid){
firebase.firestore().collection(`users/${getters.uid}/addresses`).doc(id).update(address).then*1
})
},
login () {
const google_auth_provider = new firebase.auth.GoogleAuthProvider()
firebase.auth().signInWithRedirect(google_auth_provider)
},
logout () {
firebase.auth().signOut()
},
deleteLoginUser ({ commit }) {
commit('deleteLoginUser')
},
toggleSideMenu ({ commit }) {
commit('toggleSideMenu')
},
addAddress ({ getters, commit }, address) {
 
if (getters.uid) {
firebase.firestore().collection(`users/${getters.uid}/addresses`).add(address).then(doc => {
commit('addAddress', { id: doc.id, address })
})
}
},
updateAddress({getters, commit},{id, address}){
if(getters.uid){
firebase.firestore().collection(`users/${getters.uid}/addresses`).doc(id).update(address).then*2{
this.deleteAddress({id})
}
},
...mapActions(['deleteAddress'])
}
}
</script>

 

追加場所

ゴミ箱アイコンを追加

<v-icon small class='mr-2' @click='deleteConfirm(item.id)'>mdi-delete</v-icon>
 

 

mapActionsをインポート

import {mapActions} from 'vuex'
 

クリックイベント(ゴミ箱)を追加

methods:{
deleteConfirm(id){
if(confirm('削除してよろしいですか?')){
this.deleteAddress({id})
}
},
...mapActions(['deleteAddress'])
}

 

これで削除機能を実装

f:id:kirikko_Scondcube:20200803193703p:plain

f:id:kirikko_Scondcube:20200803193712p:plain

firebase hostingでの公開方法

 

npm install -g firebase-tools

これでfirebaseのコマンドを使用できるようにする

firebase login

プロダクトの場所(今回はsample-app)へ移動

firebase init

f:id:kirikko_Scondcube:20200803194208p:plain

Hostingを選択しスペースキーで選択→エンターで決定

use exist projectを選択し、以下の自分のプロジェクトを選ぶ

f:id:kirikko_Scondcube:20200803194504p:plain

↓ここではyを押してエンター

f:id:kirikko_Scondcube:20200803194437p:plain

↓distと入力しエンター(何も入れないとpublicが選択される)

f:id:kirikko_Scondcube:20200803194628p:plain

これで設定完了

 

次に

npm run build

これでdistフォルダが作成されdistフォルダ以下にコンパイルされたファイルが配置され、先ほどdistディレクトリを公開対象に設定したので、

 

firebase deploy 

を打つことでアプリケーションを公開できる。

 

 

公開したアプリケーションの停止方法

firebase hosting:disable

 

このコマンドで公開を停止できる

 

サイド公開するときはfirebase deploy

 

 

*1:) => {

commit('updateAddress', {id, address})
})
}
}
},
getters: {
userName: state => state.login_user ? state.login_user.displayName : '',
photoURL: state => state.login_user ? state.login_user.photoURL : '',
uid: state => state.login_user ? state.login_user.uid:null,
getAddressById: state => id => state.addresses.find(address => address.id === id)
},
modules: {
}
})

 

追加箇所は

actionsの

updateAddress({getters, commit},{id, address}){
if(getters.uid){
firebase.firestore().collection(`users/${getters.uid}/addresses`).doc(id).update(address).then(() => {
commit('updateAddress', {id, address})
})
}
}

 

mutationsの

updateAddress(state, {id, address}){
const index = state.addresses.findIndex(address => address.id === id)
state.addresses[index] = address
}

 

AddressForm.vue

<template>
<v-container text-xs-center>
<v-layout row wrap justify-center>
<v-flex xs12 class="text-center">
<h1>連絡先編集</h1>
</v-flex>

<v-flex xs5 mt-5>
<v-card>
<v-card-text>
<v-form>
<v-text-field v-model="address.name" label="名前"></v-text-field>
<v-text-field v-model="address.tel" label="電話番号"></v-text-field>
<v-text-field v-model="address.email" label="メールアドレス"></v-text-field>
<v-text-field v-model="address.address" label="住所"></v-text-field>
<div class="text-center">
<v-btn @click="$router.push({ name: 'addresses' })">キャンセル</v-btn>
<v-btn color="info" class="ml-2" @click="submit">保存</v-btn>
</div>
</v-form>
</v-card-text>
</v-card>
</v-flex>
</v-layout>
</v-container>
</template>

<script>
import { mapActions } from 'vuex'

export default {
created(){
if(!this.$route.params.address_id)return
 
const address = this.$store.getters.getAddressById(this.$route.params.address_id)
if(address){
this.address = address
}else{
this.$router.push({name:'addresses'})
}
},
data () {
return {
address: {}
}
},
methods: {
submit () {
if(this.$route.params.address_id){
this.updateAddress({id: this.$route.params.address_id, address: this.address})
}else{
this.addAddress(this.address)
}
this.$router.push({ name: 'addresses' })
this.address = {}
},
...mapActions(['addAddress', 'updateAddress'])
}
}
</script>

 

追加箇所

...mapActions(['addAddress', 'updateAddress'])
 

updateAddressを追加

submit () {
if(this.$route.params.address_id){
this.updateAddress({id: this.$route.params.address_id, address: this.address})
}else{
this.addAddress(this.address)
}
this.$router.push({ name: 'addresses' })
this.address = {}
},

submit配下にif,else文を追加

 

これで更新処理ができるようになる

 

削除処理の実装

store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
import firebase from 'firebase'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
login_user: null,
drawer: false,
addresses: []
},
mutations: {
setLoginUser (state, user) {
state.login_user = user
},
deleteLoginUser (state) {
state.login_user = null
},
toggleSideMenu (state) {
state.drawer = !state.drawer
},
addAddress (state, { id, address }) {
address.id = id
state.addresses.push(address)
},
updateAddress(state, {id, address}){
const index = state.addresses.findIndex(address => address.id === id)
state.addresses[index] = address
},
deleteAddress(state, {id}){
const index = state.addresses.findIndex(address => address.id === id)
state.addresses.splice(index,1)
}
},
actions: {
setLoginUser ({ commit }, user) {
commit('setLoginUser', user)
},
fetchAddresses ({ getters, commit }) {
firebase.firestore().collection(`users/${getters.uid}/addresses`).get().then(snapshot => {
snapshot.forEach(doc => commit('addAddress', { id: doc.id, address: doc.data() }

*2:) => {

commit('updateAddress', {id, address})
})
}
},
deleteAddress({getters, commit},{id}){
if(getters.uid){
firebase.firestore().collection(`users/${getters.uid}/addresses`).doc(id).delete().then(() => {
commit('deleteAddress', {id})
})
}
}
},
getters: {
userName: state => state.login_user ? state.login_user.displayName : '',
photoURL: state => state.login_user ? state.login_user.photoURL : '',
uid: state => state.login_user ? state.login_user.uid:null,
getAddressById: state => id => state.addresses.find(address => address.id === id)
},
modules: {
}
})

 

ミューテンションに

deleteAddress(state, {id}){
const index = state.addresses.findIndex(address => address.id === id)
state.addresses.splice(index,1)
}

 

アクションズに

deleteAddress({getters, commit},{id}){
if(getters.uid){
firebase.firestore().collection(`users/${getters.uid}/addresses`).doc(id).delete().then(() => {
commit('deleteAddress', {id})
})
}
}

上記を追加

 

views/Address.vue

<template>
<v-container text-xs-center justify-center>
<v-layout row wrap>
<v-flex xs12>
<h1>連絡先一覧</h1>
</v-flex>

<v-flex xs12 mt-5 mr-5 text-right>
<router-link :to="{ name: 'address_edit' }">
<v-btn color="info">
連絡先追加
</v-btn>
</router-link>
</v-flex>


<v-flex xs12 mt-5 justify-center>
<v-data-table :headers='headers' :items='addresses'>
<template v-slot:item.action="{ item }">
<router-link :to="{ name: 'address_edit', params: { address_id: item.id }}">
<v-icon small class="mr-2">mdi-pencil</v-icon>
</router-link>
<v-icon small class='mr-2' @click='deleteConfirm(item.id)'>mdi-delete</v-icon>
</template>
</v-data-table>
</v-flex>
</v-layout>
</v-container>
</template>

<script>
import {mapActions} from 'vuex'
export default {
created () {
this.addresses = this.$store.state.addresses
},
data () {
return {
headers: [
{ text: '名前', value: 'name' },
{ text: '電話番号', value: 'tel' },
{ text: 'メールアドレス', value: 'email' },
{ text: '住所', value: 'address' },
{ text: '操作', value: 'action', sortable: false }
],
addresses: []
}
},
methods:{
deleteConfirm(id){
if(confirm('削除してよろしいですか?'