Storing your notes in the Cloud Firestore with Vue.js

Fire the base of Vue.js! - 2 Part Series

In my recent article, we built a Notes Writer Vue.js app that demonstrated how Mirage.js (an in-memory client-side server library) simulates REST API responses for your client-side app.

Now, we will take the Notes Writer app to another level by introducing the Cloud Firestore. Firestore is a serverless database service, offered by Google Firebase. We'll use the Cloud Firestore as a backend database for this app to persist and manage the notes.

As you go through the article, it will be clear that only the code for the Vuex Store is affected by introducing Cloud Firestore to the app. Some functions become void, and the entire code becomes simpler.

This article assumes a basic knowledge of using the Firebase Firestore library API. If you need some additional clarification, I’ve made sure to include some hyperlinks to help you locate what you want, and learn it quickly.

The source code of this article can be cloned from this GitHub repo: Notes Writer.

Google Firebase

The Cloud Firestore is a member of the Google Firebase family. Google Firebase is a Mobile and Web development platform offering cloud-based services to quicken the development process. Some of the products include:

Cloud Firestore

A serverless real-time NoSQL database engine.

Authentication

An authentication engine that is capable of authenticating your users via social networks like Google, Twitter, and Facebook, to mention a few. (https://firebase.google.com/docs/auth).

Cloud Functions

A platform and engine to build, deploy and run Cloud Functions with Google Firebase.

Hosting

A platform to host your application, whether the app is a static or dynamic app. This platform offers a rich toolbox to test your apps locally before deploying them live.

Cloud Storage

This service offers developers a bucket to store and serve user-generated content, such as photos, videos, or any other type of files.

ML Kit

A new member in the Google Firebase family. This service allows developers to introduce Machine Learning services to help solve real-life complex problems.

Documentation

The Google Firebase team has done a great job offering detailed, and quality documentation, covering all aspects of Firebase. Instead of repeating the same material here, I'll provide the relevant links that will bring you up to speed on Cloud Firestore and Firebase in general.

How to add and setup Firebase in your app Cloud Firestore docs Firebase API reference Firebase Libraries Firebase App samples

Moving on, we will be using the Cloud Firestore as both a database engine, and a real-time database to listen to new Notes that are being added to the app.

Demo

Let’s start by creating a new Git branch by running this command:

git checkout -b firebase-firestore-integration

The command creates and checks out a new Git branch.

Install Firebase

There are several approaches to incorporating Firebase in your app. I will install the Firebase NPM package. Let’s go ahead and install this package by running the command:

npm install --save firebase

This installs all that's required to start developing with Firebase.

Create a new Firebase project

Before you start using any Firebase service, you must create a new Firebase project. Visit the Firebase Website by pasting the following URL in your browser: Firebase Website.

If you are not signed in, you will be redirected to the Sign in/up page. Right after signing in, you are transferred to the Firebase home page.

Click the Go to console hyperlink to get started.

Click the Add project tile to start creating your first Firebase project.

Screenshot 2019-12-13 at 10.18.38 PM

Fill in a name for the new project and accept the Firebase terms and conditions. Once done, click Continue.

Screenshot 2019-12-13 at 10.20.39 PM

In the next step, I chose to disable the Google Analytics. You are free to enable it.

On the Google Analytics page, locate the Create project button to establish the project. The process usually takes a few seconds to finish setting up everything.

A new screen shows up with information about the creation process. Once the new project is ready, click the Continue button to go the project page.

Screenshot 2019-12-13 at 10.26.02 PM

Expand the Develop menu. You will be spending most of your time using the features under this menu, and specifically, the Database menu options in this article.

Create a new Firebase Web app

Now that the Firebase project is created, it’s time to create your first Firebase Web app. A Firebase project consists of multiple apps. For instance, an iOS Mobile backend app, Android Mobile backend app, Web backend app, and other types of apps.

For this project, we will be creating a Web backend app. Locate and click the gear icon near the Project Overview menu item. Then, click the Project Setting hyperlink to go to the project settings.

Screenshot 2019-12-13 at 10.35.43 PM

On the Project Settings page, you can check the project settings, Web API key, Project ID, and other project-related information.

Under the General tab, scroll down to reach the Your apps section. Click the Web App icon as shown below.

Screenshot 2019-12-13 at 10.38.29 PM

A new screen pops up to collect some information about your new app before it gets registered under Firebase.

Screenshot 2019-12-13 at 10.40.58 PM

Provide a name for the new app. Also, select the option to set up Firebase Hosting for this app. We might be using this option later, but it’s better to select it now.

Locate and click the Register app button to get started registering the new app.

You may skip the scripts section, and click the Next button right away.

Screenshot 2019-12-13 at 10.43.25 PM

You are then asked to install the Firebase CLI that we might use later on to host the Notes Writer app on Firebase.

Copy the command and run it locally on your computer to install it globally.

Locate the Next button on the screen to move forward. You are given detailed information on how to deploy your app to Firebase. We will skip these steps for now, and come back to it later.

Screenshot 2019-12-13 at 10.48.09 PM (1)

Click the Continue to console button to start managing your new app.

You are redirected back to the Project Settings page. Scroll down until you find your new Web app section. Locate the section Firebase SDK snippet, and make sure the config option is selected:

Screenshot 2019-12-13 at 10.56.51 PM

The firebaseConfig object has all the settings needed to allow your client-side app to connect to Firebase.

Copy this object, go back to the code editor, and create a new file named firebaseConfig.js at the root folder of your app. Then, paste this object inside the file. We will revisit this file shortly.

Create the database

Now that the app is ready, we are free to create an instance of the Cloud Firestore database.

Locate and click the Database menu item under the Develop menu.

Screenshot 2019-12-13 at 11.24.44 PM

Click the Create database button to create a new database.

Screenshot 2019-12-13 at 11.26.01 PM

On the Create database Modal window, make sure you select the Start in test mode option. This removes any restrictions on reading, adding, deleting, and editing data inside the database. Once you are ready for production, you may revisit the database settings, enable the production mode, and define rules for user access permissions.

Click the Next button to select a geographical location for this new database.

Screenshot 2019-12-13 at 11.28.38 PM

Make sure to select the nearest location to you. Finally, click the Done button. Firebase takes a few seconds to provision the new database. Then, you are redirected to the new Database page to start managing the data.

Historically, Firebase supported a realtime database engine. The Cloud Firestore is a successor to that engine, and is the recommended option for almost all scenarios. You can read more about the Firebase Realtime Database.

Screenshot 2019-12-13 at 11.39.05 PM

Just as a Relational Database engine structures and defines data in terms of Tables, Rows, and Columns, the Cloud Firestore is a NoSQL database engine structures that defines data in terms of Collections, Documents, and the relationships between Documents and Collections.

Let’s create the Notes collection by clicking the Start collection hyperlink.

Screenshot 2019-12-13 at 11.46.00 PM

Give your new collection the name of notes. Then click the Next button.

Screenshot 2019-12-13 at 11.49.36 PM

Create your first Document by adding the fields that you want to appear on a single Note record. Notice that the Document ID can be auto generated by Firestore, or you can give it a unique value yourself. I choose to keep it managed by Firestore.

Starting by adding the body and title fields. Give them both the string data type, and fill in a value.

You may add more fields. In this case, I will add the createdOn and updatedOn fields of type timestamp.

Screenshot 2019-12-13 at 11.51.20 PM

Once done filling the data, click the Save button.

Screenshot 2019-12-13 at 11.52.05 PM

You can now see our new notes collection together with the first document added, and the details of that document.

You may add more Notes documents by clicking the Add document hyperlink. You will follow the same process to add new Documents.

Now that the database is up and running, let's go back to the Notes Writer app, and start refactoring the code to make use of the Firestore database to load and manage Note in the app.

Connect app to Firebase

It’s time now to start interacting with the Firebase Firestore from within our Notes Writer app.

Revisit the firebaseConfig.js file at the root of the application folder, and paste the following:

import firebase from 'firebase/app'
import 'firebase/firestore'

// firebase init
const firebaseConfig = {
    ....
...
};

firebase.initializeApp(firebaseConfig)

// firebase utils
const db = firebase.firestore()

// firebase collectionsa
const notesCollection = db.collection('notes')

export {
    firebase,
    db,
    notesCollection
}

Make sure to copy your own firebaseConfig object from the Firebase app settings.

Start by importing the firebase object, and also the firebase/firestore library.

Given that you have copied and pasted a valid firebaseConfig object, initialize the communication with Firebase by calling the firebase.initializeApp() function, passing the firebaseConfig object as a parameter.

Store an instance of the Firestore client API inside a variable named db.

Also, retrieve a reference to the notes collection, and store it inside the variable named notesCollection.

Finally, export a few objects to be imported and used in other places in the app.

Open the /store/index.js file. Import the firebaseConfig file at the top of the store as follows:

const fb = require('./../firebaseConfig.js')

We are going to use the realtime database feature to get notified when new Notes documents are created so that we load them inside the store. Add the following section outside the store object:

fb.notesCollection.orderBy('createdOn', 'desc').onSnapshot(querySnapshot => {
  let notesArray = []

  querySnapshot.forEach(doc => {
    let note = doc.data()
    note.id = doc.id
    notesArray.push(note)
  })

  store.commit('loadNotes', notesArray)
})

The key here is to use the onSnapshot() function that is accessible on the notesCollection object.

Whenever a new document is added, updated or deleted, the onSnapshot() callback is called with all the information encapsulated inside the querySnapshot variable.

The code loops over all the Notes documents returned, populates an array of all notes, and then commits the array to the store by calling the mutation loadNotes.

Any time me or someone else creates, updates, or deletes a Note document, the onSnapshot() callback is executed, and therefore, our store is always up to date.

The loadNotes mutation is defined as follows:

   loadNotes (state, notes) {
      state.notesList = notes
    },

I’ve amended the states object to include the following:

 state: {
    notesList: [],
    note: {},
    performingDelete: false,
    performingAdd: false,
    performingUpdate: false
  },

The store now tracks a boolean flag to know whether there is an active request to either delete a Note, add a Note, or update a Note. These flags can be used to show/hide UI in the app, and give a visual feedback to the user of the app.

The deleteNote action is defined as follows:

async deleteNote ({ commit, state }) {
      let id = (state.note && state.note.id)

      if (id) {
        try {
          commit('setPerformingDelete', true)
          await fb.notesCollection.doc(id).delete()
          commit('setPerformingDelete', !state.performingDelete)
        } catch (error) {
          console.error(error)
        }
      }

      commit('setNote', {})
    },

The action starts by retrieving the note’s details to delete. If there is a valid Note Id, it continues. It starts by setting the setPerformingDelete state flag to true. It issues a call on the Firebase client API to delete a document specifying the Note document ID. It then toggles the value of the setPerformingDelete’ state flag back tofalse`, signaling the end of deleting a Note document request. Finally, the action resets the current active Note to clear the display.

The entire code is wrapped inside atry/catch block.

Notice though we are not manually removing the Note document from the Store state. Instead, we just issue a request to delete the Note document. The new list of Notes Documents will be retrieved via the onSnapshot() realtime database feature. Less code for you to write now!

Let’s implement the saveNote action:

async saveNote ({ commit, state }) {
      const { id, body, title } = state.note

      if (id) { // update
        commit('setPerformingUpdate', true)
        await fb.notesCollection.doc(id).update({
          body,
          title,
          updatedOn: fb.firebase.firestore.Timestamp.now()
        })
        commit('setPerformingUpdate', !state.performingUpdate)
      } else { // add
        commit('setPerformingAdd', true)
        await fb.notesCollection.add({
          body,
          title,
          createdOn: fb.firebase.firestore.Timestamp.now(),
          updatedOn: fb.firebase.firestore.Timestamp.now()
        })
        commit('setPerformingAdd', !state.performingAdd)
      }

      commit('setNote', {})
    }

The code distinguishes between updating an existing Note document or adding a new one. In both cases, we set the flag to whether the app is updating a record inside Firebase Firestore or adding a new one.

In case we are updating an existing Note document, the code calls the update() function on the Note document reference. The updatedOn field is set to a value of fb.firebase.firestore.Timestamp.now().

From the Firebase documentation:

A Timestamp represents a point in time independent of any time zone or calendar, represented as seconds, and fractions of seconds at nanosecond resolution in UTC Epoch time.

You can read more information on firebase.firestore.Timestamp In case we are adding a new Note document, the code calls the add() function on the noteColletion object passing as input a Note object including values for createdOn and updatedOn.

Finally, the action resets the current active Note to clear the display.

You can review the entire store file on Github. One minor change I introduced to the store is removing the getters, and directly accessing state data. If a getter is not doing any logic, there is no need to keep this getter. Simply access the state data directly. Thank you, Simone, for bringing this to my attention!

Conclusion

This article demonstrates how to integrate Firebase Firestore into your front-end app by giving a step-by-step guide of what's required to create a Firebase app, add a Firestore database, and connect the app to Firebase.

Very soon, I will be using the Firebase Authentication to allow users to login to the Notes Writer app, and manage their own set of Notes, independent of other users using the same app.

Stay tuned!

This Dot Labs is a modern web consultancy focused on helping companies realize their digital transformation efforts. For expert architectural guidance, training, or consulting in React, Angular, Vue, Web Components, GraphQL, Node, Bazel, or Polymer, visit [thisdotlabs.com]((https://www.thisdotlabs.com).

This Dot Media is focused on creating an inclusive and educational web for all. We keep you up to date with advancements in the modern web through events, podcasts, and free content. To learn, visit thisdot.co.

You might also like