Building Real Time Single Page Web Applications With Vue.js 2 and Firebase

Firebase is a mobile and web application platform supporting developers with various tools and services to build high-quality app. A central feature of Firebase is the realtime database. By using the Firebase API the realtime database can be used to store and sync data across multiple clients and platforms. The Firebase website is available at: https://firebase.google.com/.

Firebase is a perfect match for Vue.js. The realtime database can be used as a backend for the view layer which is implemented with Vue.js 2. To integrate Firebase services with your Vue.js 2 application The VueFire library can be used.

In the following you’ll learn how to set up a Firebase realtime database and bind to real time data in your Vue application by using this library step-by-step.

What We’re Going To Build

The application we’re going to build in this tutorial can be seen in the following:

That’s a simple book manager application printing out a list of books (with a link to the corresponding website). The books data are retrieved from the Firebase database. The user is able to add new books to the list and delete existing entries. The data is stored inside a Firebase database and all database operations are synced in real time across all application instances.

To build up the user interface of the application we’re using the Bootstrap Framework. To show toast notification to the user after a book has been deleted successfully the Toastr JavaScript library is used:

Setting Up Firebase

Before starting to implement the Vue application, we first need to setup the Firebase real time database.

To set up Firebase you first need to go to https://firebase.google.com/ create an account and login to the Firebase console. The Firebase console gives you access to all firebase services and configuration options. First, we need to create a new Firebase project:

Once created a project you can click on the project tile and you’ll be redirected to the Firebase project console:

The project console is the central place for the Firebase configuration settings. From the menu on the left side you can access the various Firebase services. Click on the link Database to access the realtime database view. You can use the online editor to add content to the database, e.g.:

As you can see the data in the realtime database is organized in a hierarchical tree which contains nodes and key-value-pairs. This is similar to a JSON data structure. Under the root node add a sub node items. Under items create a few key-value-pairs like you can see it in the screenshot. We’ll use these data elements in our sample application later on.

Finally, we need to edit the security rules of the database, so that we’re able to access data without authentication later on in our Angular 2 sample application. Switch to the tab Rules and edit the given security rules to correspond to the following:

{

"rules": {

".read": true,

".write": true

}

}

Now read and write database access is possible without authentication.

Setting Up a Vue.js 2 Project (With Vue CLI)

With the Firebase real time database prepared we’re now ready to go and start the implementation of the view layer. To initiate a new Vue.js 2 project the easiest way is to use Vue CLI:

$ vue init webpack vuejs-firebase-01

A new project directory vuejs-firebase-01 is created and the Vue Webpack template is downloaded into that directory. We need to complete the project setup by changing into that directory and executing the following command:

$ npm install

This makes sure that all dependencies are downloaded and installed into the node_modules subfolder.

Adding Firebase And VueFire Library To The Project

The VueFire library (https://github.com/vuejs/vuefire) makes it easy to bind Firebase data to Vue.js data properties. To add VueFire and the Firebase core library to the project execute the following command within the project directory:

$ npm install firebase vuefire --save

In file main.js we’re now able to import VueFire. It’s also needed to call Vue.use(VueFire) to make the library available in the project:

import Vue from 'vue' import VueFire from 'vuefire' import App from './App' Vue.use(VueFire) new Vue({ el: '#app', template: '<App/>', components: { App } })

Adding Bootstrap To The Project

Because we’d like to use Bootstrap CSS and components within our sample app, we also need to add this framework to the project. To add the framework in our project we need to include the corresponding CSS and JavaScript file in index.html. The resources can be retrieved from a CDN as you can see in the following:

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>vuejs-firebase-01</title> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> </head> <body> <div id="app"></div> <!-- built files will be auto injected --> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script> </body> </html>

Connecting To Firebase

With all libraries added to the project, we’re now able to establish a connection to the Firebase database. Let’s add the following code inside the script section in file App.vue:

import Firebase from 'firebase' let config = { apiKey: "...", authDomain: "...", databaseURL: "...", storageBucket: "...", messagingSenderId: "..." }; let app = Firebase.initializeApp(config) let db = app.database() let booksRef = db.ref('books')

First, we’re importing Firebase from the core firebase library. To create an Firebase instance we’re using the factory method initializeApp. This method expects a configuration object containing the following properties: apiKey, authDomain, databaseURL, storageBucket and messagingSenderId. The property values needs to be set according to the Firebase project which has been created. You can retrieve the values from the Firebase console very easily. Open the project overview page and click on the link Add Firebase to your web app.

In the opening pop-up window you get a prefilled config object in JSON notation.

With the Firebase instance stored in app we’re now able to retrieve a database reference by using the app.database() call. With the database reference available, finally we’re able to retrieve a reference to the books node in our database:

let booksRef = db.ref('books')

Implementing Book List Output

The VueFire library makes it very easy to bind Vue.js properties to Firebase data. Just add the following to component configuration object:

firebase: { books: booksRef },

Now the books variable gives us access to the books items from the Firebase database, so that we can output the data in the template:

<div class="panel-body"> <table class="table table-striped"> <thead> <tr> <th>Title</th> <th>Author</th> </tr> </thead> <tbody> <tr v-for="book in books"> <td><a v-bind:href="book.url">{{book.title}}</a></td> <td>{{book.author}}</td> </tr> </tbody> </table> </div>

Just use v-for directive to iterate over the elements available in books in generate a new table row for each book item.

Implementing Book Input form

Next, let’s see how new elements can be added to the real time database. First we’re defining the data model:

data () { return { newBook: { title: '', author: '', url: 'http://' } } },

Next, the corresponding input form is implemented in the component’s template:

<div class="panel panel-default"> <div class="panel-heading"> <h3 class="panel-title">Add New Books</h3> </div> <div class="panel-body"> <form id="form" class="form-inline" v-on:submit.prevent="addBook"> <div class="form-group"> <label for="bookTitle">Title:</label> <input type="text" id="bookTitle" class="form-control" v-model="newBook.title"> </div> <div class="form-group"> <label for="bookAuthor">Author:</label> <input type="text" id="bookAuthor" class="form-control" v-model="newBook.author"> </div> <div class="form-group"> <label for="bookUrl">Url:</label> <input type="text" id="bookUrl" class="form-control" v-model="newBook.url"> </div> <input type="submit" class="btn btn-primary" value="Add Book"> </form> </div> </div>

The HTML form consists of three input elements for book properties title, author and url. By using the v-model directive the newBook properties are bound to the corresponding input controls.

By using the v-on directive the submit event is bound to the event handler method addBook. To implement addBook add a methods property to the component’s configuration object and assign an object containing the implementation of addBook.

methods: { addBook: function () { booksRef.push(this.newBook); this.newBook.title = ''; this.newBook.author = ''; this.newBook.url = 'http://'; }, },

As we’ve used data binding to sync the value of the form input controls with the newBook object, we’re able to use this object within addBook and pass it the call of method booksRef.push. This inserts the new books object into the Firebase books node and syncs the data across all connected client instances of the application automatically.

Implementing Delete Function

In the next step, let’s extend the implementation and add a delete function, so that the user is able to delete entries from the books table. First add another column to the table, displaying an icon on which the user can click to delete the entry:

<td><span class="glyphicon glyphicon-trash" aria-hidden="true" v-on:click="removeBook(book)"></span></td>

Again, we’re using the v-on directive to connect the click event to the event handler method removeBook. The method implementation can be seen in the following:

removeBook: function (book) { booksRef.child(book['.key']).remove() }

To delete a book element from the Firebase database we’re first selecting the book node by using the child method. This method is expecting to get the key of book element which should be selected. We already have access to this information via book['.key'] . Finally we need to call remove() on the returned book object to delete it from the database.

Adding Toast Notifications

For the final touch we’re adding the Toastr library to our application to present a toast notification each time a book is deleted.

Add the Toastr CSS file from a CDN in the head section of index.html:

<link href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.css" rel="stylesheet"/>

Next, add the toastr NPM package to the project and save that dependency in package.json:

$ npm install toastr --save

Now we’re able to add the following import statement on top of the script section in App.vue:

import toastr from 'toastr'

Inside of removeBook the call of method toastr.success makes sure that a notification is shown:

removeBook: function (book) { booksRef.child(book['.key']).remove() toastr.success('Book removed successfully') }

Summary

Adding all pieces together you’ll end up with the following code inside of Vue.app:

<template> <div id="app" class="container"> <div class="page-header"> <h1>Vue.js 2 & Firebase <small>Sample Application by CodingTheSmartWay.com</small></h1> </div> <div class="panel panel-default"> <div class="panel-heading"> <h3 class="panel-title">Add New Books</h3> </div> <div class="panel-body"> <form id="form" class="form-inline" v-on:submit.prevent="addBook"> <div class="form-group"> <label for="bookTitle">Title:</label> <input type="text" id="bookTitle" class="form-control" v-model="newBook.title"> </div> <div class="form-group"> <label for="bookAuthor">Author:</label> <input type="text" id="bookAuthor" class="form-control" v-model="newBook.author"> </div> <div class="form-group"> <label for="bookUrl">Url:</label> <input type="text" id="bookUrl" class="form-control" v-model="newBook.url"> </div> <input type="submit" class="btn btn-primary" value="Add Book"> </form> </div> </div> <div class="panel panel-default"> <div class="panel-heading"> <h3 class="panel-title">Book List</h3> </div> <div class="panel-body"> <table class="table table-striped"> <thead> <tr> <th>Title</th> <th>Author</th> <th></th> </tr> </thead> <tbody> <tr v-for="book in books"> <td><a v-bind:href="book.url">{{book.title}}</a></td> <td>{{book.author}}</td> <td><span class="glyphicon glyphicon-trash" aria-hidden="true" v-on:click="removeBook(book)"></span></td> </tr> </tbody> </table> </div> </div> </div> </template> <script> import Hello from './components/Hello' import Firebase from 'firebase' import toastr from 'toastr' let config = { apiKey: "...", authDomain: "...", databaseURL: "...", storageBucket: "...", messagingSenderId: "..." }; let app = Firebase.initializeApp(config) let db = app.database() let booksRef = db.ref('books') export default { name: 'app', firebase: { books: booksRef }, data () { return { newBook: { title: '', author: '', url: 'http://' } } }, methods: { addBook: function () { booksRef.push(this.newBook); this.newBook.title = ''; this.newBook.author = ''; this.newBook.url = 'http://'; }, removeBook: function (book) { booksRef.child(book['.key']).remove() toastr.success('Book removed successfully') } }, components: { Hello } } </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; color: #2c3e50; margin-top: 20px; } </style>

Summary

Vue.js 2 makes it easy to implement the view layer of single page web application. As Vue makes no assumption of the backend technology, it can be used together with different application stacks. If you want to have real-time data synchonisation in your application Firebase is a great option for building your backend.