This post is mainly to show the implementation of Vuexfire with the help of simple notes creating application.
I would like to keep it simple and not to add rich features in Notes app as our main focus is on Vuexfire.
So, what is Vuexfire?. lets check it directly from the official document about what it does.
Vuexfire is a small and pragmatic solution to create realtime bindings between a Firebase RTDB or a Firebase Cloudstore and your Vuex store. Making it straightforward to always keep your store state in sync with remotes databases.
Firestore provides two types of databases, Firebase RTDB &Firebase Cloudstore . Vuexfire supports both of them but we will stick to Firebase Cloudstore in this tutorial.
Installing Vuexfire and firebase
In order to get started make sure to install the latest version of Vuexfire as well as firebase:
npm install vuexfire firebase
Create a cloudfire store project
In order to access the cloudfire store we need to create a project in firebase
Select create a project
give a name to the project
create a app in the project by selecting </>
button
give a name to the app
firestore configuration code fill be generated, save this somewhere,we will use it later in the application
once everything is created, Select Cloud Firestore in the homepage
Select start in test mode as we are not implementing any authentication in our application
Creating Vue App
To have a nice look i have used my all time favorite css framework W3.CSS. Those who are new to css framework i would strongly recommend you to have a look at W3.CSS
Make sure Vuex is added to the project. If not add as follow
npm install vuex --save
lets create a seperate component Notes.Vue
for notes item and import it in the Home page, App.vue
Notes.Vue
<template>
<div class="w3-col w3-container w3-margin-top">
<div class="w3-card-2 w3-round-large">
<div v-if="!isEditing">
<header class="w3-container w3-light-grey mineader headerStyle">
<h3 class="w3-text-indigo">{{ noteItem.title }}</h3>
</header>
<div class="w3-container w3-text-grey minContainer">
<p>{{ noteItem.content }}</p>
<hr />
<div class="w3-rest">
<button
@click="removeNote"
class="w3-right w3-margin-left w3-margin-bottom"
>
<i class="fa fa-trash w3-text-indigo" aria-hidden="true"></i>
</button>
<button
@click="editNote"
class="w3-right w3-margin-left w3-margin-bottom"
>
<i
class="fa fa-pencil-square-o w3-text-indigo"
aria-hidden="true"
></i>
</button>
</div>
</div>
</div>
<div v-if="isEditing">
<form v-on:submit.prevent="updateNote">
<div class="w3-container">
<p>
<input
required
placeholder="Title"
type="text"
class="w3-input w3-padding w3-border w3-round-large"
v-model="noteItem.title"
/>
</p>
</div>
<div class="w3-container w3-text-grey">
<textarea
required
v-model="noteItem.content"
placeholder="Notes"
class="w3-input w3-border w3-round-large"
cols="30"
rows="3"
></textarea>
<hr />
<div class="w3-rest">
<button class="w3-right w3-margin-left w3-margin-bottom">
<i class="fa fa-floppy-o w3-text-indigo" aria-hidden="true"></i>
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</template>
<script>
export default {
props: ["noteItem"],
data() {
return {
isEditing: false,
};
},
methods: {
removeNote() {
this.$emit("remove");
},
editNote() {
this.isEditing = true;
},
updateNote() {
this.isEditing = false;
this.$emit("update");
},
},
};
</script>
for deleting and updating note data we are emitting the event to parent component App.vue
App.vue
<template>
<div id="app">
<div class="w3-top">
<div class="w3-bar w3-indigo" style="letter-spacing:4px;">
<h3 class="w3-bar-item">Notes</h3>
</div>
</div>
<a
@click="openModal"
class="addNew w3-display-bottomright w3-margin-bottom w3-margin-right w3-button w3-xlarge w3-circle w3-pink w3-card-4"
>+</a
>
<div id="noteModal" class="w3-modal">
<div class="w3-modal-content w3-round-large w3-card-4">
<div class="w3-container">
<form v-on:submit.prevent="addNote">
<p>
<label>Title</label>
<input
required
v-model="note.title"
class="w3-input w3-border w3-round-large"
type="text"
/>
</p>
<p>
<label>Note</label>
<textarea
v-model="note.content"
required
class="w3-input w3-border w3-round-large"
id=""
cols="30"
rows="3"
></textarea>
</p>
<div class="w3-bar w3-padding-16">
<button
type="submit"
class="w3-button w3-indigo w3-right w3-margin-right w3-round"
>
Add
</button>
<button
type="button"
@click="CloseModal"
class="w3-button w3-indigo w3-right w3-margin-right w3-round"
>
Cancel
</button>
</div>
</form>
</div>
</div>
</div>
<div class="w3-container w3-row-padding notes">
<div
is="notes-item"
v-for="note in Notes"
v-bind:key="note.id"
:noteItem="note"
@delete="deleteNote(note.id)"
@update="updateNote(note)"
></div>
</div>
</div>
</template>
<script>
import Notes from "./components/Notes.vue";
import { store } from "./store";
export default {
name: "App",
components: {
"notes-item": Notes,
},
data() {
return {
note: {
title: "",
content: "",
},
};
},
computed: {
Notes() {
return store.state.notes;
},
},
methods: {
openModal() {
document.getElementById("noteModal").style.display = "block";
},
clearModal() {
this.note = {
title: "",
content: "",
};
},
CloseModal() {
this.clearModal();
document.getElementById("noteModal").style.display = "none";
},
addNote() {
store.dispatch("addNote", this.note);
this.CloseModal();
},
updateNote(payload) {
store.dispatch("updateNote", payload);
},
deleteNote(payload) {
store.dispatch("deleteNote", payload);
},
},
created() {
store.dispatch("bindNotes");
},
};
</script>
for creating,updating & deleting notes we will dispatch the actions to the Vuex store in App.vue
as follow.
addNote() {
store.dispatch("addNote", this.note);
this.CloseModal();
},
updateNote(payload) {
store.dispatch("updateNote", payload);
},
deleteNote(payload) {
store.dispatch("deleteNote", payload);
},
To bind the notes data with the data already stored in firestore, dispatch an action in Created
life cycle hook as follow
created() {
store.dispatch("bindNotes");
},
with this basic implementation of app is done. we need to configure firestore in the application to save the data.
Configuring firestore
lets create a db.js
file and add the firestore configuration data which we saved during firestore DB creation in the firebase console.
import firebase from 'firebase/app'
import 'firebase/firestore'
// Your web app's Firebase configuration
const firebaseConfig = {
apiKey: "AIzaSyBTXjgfFvii2nxU05uZFcedh3PNCyy87S8",
authDomain: "vuex-notes-d9f72.firebaseapp.com",
databaseURL: "https://vuex-notes-d9f72.firebaseio.com",
projectId: "vuex-notes-d9f72",
storageBucket: "vuex-notes-d9f72.appspot.com",
messagingSenderId: "774907129389",
appId: "1:774907129389:web:f380d7e4f7c573a96a52a4"
};
// Initialize Firebase
//firebase.initializeApp(firebaseConfig);
export const db = firebase
.initializeApp(firebaseConfig)
.firestore()
const { TimeStamp, GeoPoint } = firebase.firestore
export { TimeStamp, GeoPoint }
Adding Vuexfire in the Vuex store
lets import Vuex,db,Vuexfire details into the store file
import Vue from 'vue'
import Vuex from 'vuex'
import { vuexfireMutations, firestoreAction } from 'vuexfire'
import { db } from './db'
lets create a state variable notes
as array to store the notes data
export const store = new Vuex.Store({
state: {
notes: []
},
})
Adding Mutations
In order to use Vuexfire, you must add the mutations exported by the package at the root of your store, and only there. Do not add them in any Vuex module:
export const store = new Vuex.Store({
state: {
notes: []
},
mutations: {
...vuexfireMutations,
},
})
Adding Actions
Before adding the actions in the store lets create the collection notes
in the firestore
lets create the following actions
bindNotes
:
To bind the date with the firestore data when loading the application
actions: {
bindNotes: firestoreAction(({ bindFirestoreRef }) => {
return bindFirestoreRef('notes', db.collection('notes'))
})
}
first argument in the bindFirestoreRef
function refers to the state variable which we created earlier.
addNote
To add the note data to the firestore, here we pass the note data as payload to the firestoreAction
addNote: firestoreAction((context, payload) => {
return db.collection('notes').add(payload)
}),
deleteNode
To delete the note from firestore, here we pass the note id which is created by firestore as payload.
deleteNote: firestoreAction((context, payload) => {
db.collection('notes')
.doc(payload)
.delete()
}),
updateNote
To update the note data, here we pass the note data as payload and
update the existing document in firestore which matches the payload id.
updateNote: firestoreAction((context, payload) => {
db.collection('notes')
.doc(payload.id)
.set(payload)
}),
Preview
Source code and demo are available in the following links
Top comments (1)
I have a suggestion for your App.vue so you don't have to import the store. Use mapGetters and mapActions instead.
import { mapGetters, mapActions } from 'vuex';
export default {
name: 'Notes' ,
methods: {
...mapGetters(['getNotes']),
...mapActions(['bindNotes']),
},
computed: {
Notes() {
return this.getNotes();
}
},
created() {
this.bindNotes();
}
}
Implement getNotes to simply return this.notes in your index.js
Thanks for making this. It helped me figure things out.