Vue.js Tutorial: Building Firebase Realtime Chat Web App

by Didin J. on Aug 26, 2019 Vue.js Tutorial: Building Firebase Realtime Chat Web App

A comprehensive step by step tutorial on building simple chat web app using Vue.js and Google Firebase Realtime Database with multiple chat rooms and users

A comprehensive step by step tutorial on building a simple chat web app using Vue.js and Google Firebase Realtime Database with multiple chat rooms and users. In this Vue.js tutorial, we will use the existing Google Firebase Javascript SDK that can access the Firebase Realtime-database. Previously, we have created a Vue.js Firebase tutorial CRUD web app which is a simple CRUD operation to populate Firebase Firestore Data.

List of the steps:

The flow of this Vue.js Firebase chat web app is very simple.

  1. When the user goes to the Vue.js app URL it will redirect to the login page that only has a nickname as login field.
  2. After login, redirect to select chat room page which has a list of existing chat room and a button to add a new chat room.
  3. If click on the add button, it will be redirected to the add-room page with a single room name field and submit button.
  4. If click on an item of the chat room list, it will be redirected to the chat page and start to chat with other nicknames that join or enter the chat room.
  5. Chat room contains a list of messages from all users or nicknames and a button to logout from the chat room.

For more clear explanation, you can refer to this sequence diagram.

vue.js firebase realtime chat - sequence diagram

The following tools, framework, and module are required for this tutorial:

We assume that you have already installed Node.js. Make sure Node.js command line is working (on Windows) or runnable in Linux/OS X terminal.


Setup Google Firebase Database

Next, we will set up or create a new Google Firebase project that can use the realtime database. Just open your browser then go to Google Firebase Console and you will take to this page.

Vue.js Firebase Realtime Chat - Console

From that page, click "+" add project button to create a Google Firebase project then it will be redirected to this page.

Vue.js Firebase Realtime Chat - Start Project

After filling the project name text field which our project name is "vue-chat-app" then click continue button and it will be redirected to this page.

Vue.js Firebase Realtime Chat - Skip Google Analytics

This time, choose to not add Firebase analytics for now then click Create Project button.

Vue.js Firebase Realtime Chat - not right now

Now, you have a Google Firebase Project ready to use.

Vue.js Firebase Realtime Chat - project is ready

After click Continue button it will be redirected to this page.

Vue.js Firebase Realtime Chat - Database Dashboard

While develope menu expanded in the left menu, choose "Create Database" then it will open this dialog.

Vue.js Firebase Realtime Chat - Create Database

Select "Start in test mode" then click next and it will go to the next dialog.

Vue.js Firebase Realtime Chat - Cloud Firestore Location

Select the Firebase database server location (better near you Angular server location) then click Done button. Don't forget to select or change Cloud Firestore to Realtime Database in Develop -> Database dashboard. Next, go to the Rules tab and you will see these rules values.

{
  /* Visit https://firebase.google.com/docs/database/security to learn more about security rules. */
  "rules": {
    ".read": false,
    ".write": false
  }
}

Change it to readable and writeable from everywhere for this tutorial only.

{
  /* Visit https://firebase.google.com/docs/database/security to learn more about security rules. */
  "rules": {
    ".read": "auth === null",
    ".write": "auth === null"
  }
}

Click the publish button to update or save the changes. Now, the Google Firebase database is ready to use with your Vue.js chat web app.


Install Vue-CLI 3 and Create Vue.js App

Vue-CLI is standard tooling Vue.js development. It has the features out-of-the-box support for Babel, TypeScript, ESLint, PostCSS, PWA, Unit Testing & End-to-end testing, fully configurable without the need for ejecting, allows the community to build and share reusable solutions to common needs, create, develop and manage your projects through an accompanying graphical user interface, and instantly prototype new ideas with a single Vue file. To install Vue-CLI 3 type this command from the Terminal or Node command line.

sudo npm install -g @vue/cli

or

yarn global add @vue/cli

Next, check the version to make sure that you have the 3.x version of Vue-CLI.

vue --version
3.11.0

Next, create a new Vue.js project with the name "vue-firebase-chat" by type this command.

vue create vue-firebase-chat

For now, use the default for every question that shows up in the Terminal. Next, go to the newly created folder.

cd ./vue-firebase-chat

To make sure that created Vue.js project working, type this command to run the Vue.js application.

npm run serve

or

yarn serve

You will see this page when open `http://localhost:8080/` in the browser.

Vue.js Firebase Realtime Chat - Home Page


Install and Configure the Firebase Module

We will use Firebase Javascript SDK that available as a Node module. For that, type this command to install the Firebase module after stop the running Vue.js app (press ctrl + c).

npm install --save firebase

Next, create a new file `Firebase.js` in the root of the project folder for Firebase configuration.

touch src/Firebase.js

Open and edit `src/Firebase.js` then add these imports of Firebase SDK module.

import * as firebase from 'firebase';

Add the constant variables of settings and Firebase configuration parameters after the imports declarations.

const config = {
  apiKey: "YOUR_API_KEY",
  authDomain: "YOUR_AUTH_DOMAIN",
  databaseURL: "YOUR_DATABASE_URL",
  projectId: "YOUR_PROJECT_ID",
  storageBucket: "YOUR_STORAGE_BUCKET"
};

Initialize Firebase configuration settings.

firebase.initializeApp(config);

Export this file as a module by adding this line at the end.

export default firebase;

You can find or get those configuration parameters by click on the settings (gear button) -> Project Settings to get web API key and Project ID. Click Develop -> Authentication then scrolls to Authorized domain to get authDomain value. In order to get the value of storageBucket, you have to enable or start a Storage by going to Develop -> Storage.


Add Vue.js Router

As you see in the sequence diagram before the steps, we need to navigate through the required pages. So, we will create those pages manually by creating the files and folder for them.

touch src/components/Chat.vue
touch src/components/Room.vue
touch src/components/AddRoom.vue
touch src/components/Login.vue

Next, install "vue-router" using Vue-CLI.

vue add router

Leave the question as default then finished the router installation. That Vue-CLI command added a new view folder that contains home and about also added a router.js file that contains the routing for that views and components. In our case, the home and about the view is not necessary, so we have to open and edit `router.js` then replace the imports to these imports.

import Vue from 'vue'
import Router from 'vue-router'
import Chat from './components/Chat.vue'
import Room from './components/Room.vue'
import AddRoom from './components/AddRoom.vue'
import Login from './components/Login.vue'

Change the generated routes array to accommodate the last created components.

routes: [
  {
    path: '/chat/:nickname/:roomid/:roomname',
    name: 'Chat',
    component: Chat
  },
  {
    path: '/room/:nickname',
    name: 'RoomList',
    component: Room
  },
  {
    path: '/add-room',
    name: 'AddRoom',
    component: AddRoom
  },
  {
    path: '/',
    name: 'Login',
    component: Login
  }
]

Next, remove unwanted elements from the main view by open and edit `src/App.vue` then make the Vue.js template like this.

<template>
  <div id="app">
    <router-view/>
  </div>
</template>


Bootstrap-Vue Login Page

We will Bootstrap-Vue for the theme or styling the UI of the Chat Room. Using BootstrapVue we can build responsive, mobile-first projects on the web using Vue.js and the world's most popular front-end CSS library Bootstrap v4. Type this Vue-CLI command to install the bootstrap-vue module.

vue add bootstrap-vue

Next, open and edit `src/components/Login.vue` then add the required template that contain <b-row>, <b-col>, <b-form>, <b-form>, <b-form-group>, <b-form-input>, and <b-button>.

<template>
  <b-row>
    <b-col cols="12">
      <h2>
        Login
      </h2>
      <b-jumbotron>
        <b-form @submit="onSubmit">
          <b-form-group>
            <b-form-input id="nickname" v-model.trim="login.nickname" placeholder="Enter your nickname"></b-form-input>
          </b-form-group>
          <b-button type="submit" variant="primary" :disabled="!login.nickname">Login</b-button>
        </b-form>
      </b-jumbotron>
    </b-col>
  </b-row>
</template>

Add the Vue script that contains login objects and a method to submit login to redirect to Room List page with a nickname parameter.

<script>

import router from '../router'

export default {
  name: 'AddBoard',
  data () {
    return {
      login: { nickname: '' }
    }
  },
  methods: {
    onSubmit (evt) {
      evt.preventDefault()

      router.push({
        name: 'RoomList',
        params: { nickname: this.login.nickname }
      })
    }
  }
}
</script>

Add a little style to clean up the view.

<style>
  .jumbotron {
    padding: 2rem;
  }
</style>


Bootstrap-Vue Room List & Add-Room

After login it will redirected to the room list. For that, open and edit `src/components/Room.vue` then add these bootstrap-vue template that contain <b-row>, <b-col>, <b-link> for redirect to Add Room Page, <b-list-group>, and <b-list-group-item> with iteration of room array.

<template>
  <b-row>
    <b-col cols="12">
      <h2>
        Room List
        <b-link href="/add-room">(Add Room)</b-link>
      </h2>
      <b-list-group>
          <b-list-group-item v-for="room in rooms" :key="room.key" :to="{name: 'Chat', params: {nickname: nickname, roomid: room.key, roomname: room.roomName}}" action>
              {{room.roomName}}
          </b-list-group-item>
      </b-list-group>
    </b-col>
  </b-row>
</template>

Add the Vue.js script that contains data of nickname, room array, error array, Firebase realtime-database reference to chatrooms document, and a method to load or get the list of room from the Firebase Realtime-Database.

<script>

import firebase from '../Firebase'

export default {
  name: 'BoardList',
  data () {
    return {
      nickname: this.$route.params.nickname,
      rooms: [],
      errors: [],
      ref: firebase.database().ref('chatrooms/')
    }
  },
  created () {
    this.ref.on('value', (snapshot) => {
      this.rooms = [];
      snapshot.forEach((doc) => {
        let item = doc.val()
        item.key = doc.key
        this.rooms.push(item)
      });
    });
  }
}
</script>

Add a little style to clean up the view.

<style>
  .table {
    width: 96%;
    margin: 0 auto;
  }
</style>

Next, open and edit `src/components/AddRoom.vue` then add the Bootstrap-Vue template that contains the required Bootstrap-vue <b-form> and other components to submit a new room.

<template>
  <b-row>
    <b-col cols="12">
      <h2>
        Add Room
        <b-link @click="$router.go(-1)">(Room List)</b-link>
      </h2>
      <b-jumbotron>
        <b-form @submit="onSubmit">
          <b-form-group>
            <b-form-input id="roomname" v-model.trim="room.roomName" placeholder="Enter Room Name"></b-form-input>
          </b-form-group>
          <b-button type="submit" variant="primary" :disabled="!room.roomName">Save</b-button>
        </b-form>
      </b-jumbotron>
    </b-col>
  </b-row>
</template>

Add a Vue.js script that contains Firebase realtime-database reference to chatrooms, room object, and a method to submit a new room to the Firebase realtime-database then redirect back to the Room List page.

<script>

import firebase from '../Firebase'
import router from '../router'

export default {
  name: 'AddBoard',
  data () {
    return {
      ref: firebase.database().ref('chatrooms/'),
      room: { roomName: '' }
    }
  },
  methods: {
    onSubmit (evt) {
      evt.preventDefault()

      let newData = this.ref.push()
      newData.set({
        roomName: this.room.roomName
      })
      router.go(-1)
      .catch((error) => {
        alert("Error adding document: ", error)
      });
    }
  }
}
</script>

Add a little style to adjust the view.

<style>
  .jumbotron {
    padding: 2rem;
  }
</style>


Bootstrap-Vue Chat Page

Now, we will be working on the main feature of this tutorial, that is Bootstrap-vue chat page. But first, we have to install vue-chat-scroll because we want the chat conversation always scroll to the last chat message. Type this command to install it.

yarn add vue-chat-scroll --save

or

npm install -save vue-chat-scroll

Next, open and edit `src/main.js` then add this import.

import VueChatScroll from 'vue-chat-scroll'

Register that VueChatScroll module after the Vue config.

Vue.use(VueChatScroll)

Next, open and edit `src/components/Chat.vue` then add the Bootstrap-vue template that contains the list of chat messages that iterated from the chats array, exit chat link, and the send message form.

<template>
  <b-row>
    <b-col cols="12">
      <h2>
        {{roomname}}
        <b-link @click="exitChat()">(Exit Chat)</b-link>
      </h2>
      <div class="chat-box" v-chat-scroll>
        <b-list-group>
          <b-list-group-item class="chat-item" v-for="chat in chats" :key="chat.key">
            <div class="chat-status text-center" v-if="chat.type==='join'||chat.type==='exit'">
              <span class="chat-date">{{chat.sendDate}}</span>
              <span class="chat-content-center">{{chat.message}}</span>
            </div>
            <div v-else>
              <div class="chat-message text-right" v-if="chat.user === nickname">
                <div class="right-bubble">
                  <span class="msg-name">Me</span>
                  <span class="msg-date">{{chat.sendDate}}</span>
                  <p text-wrap>{{chat.message}}</p>
                </div>
              </div>
              <div class="chat-message text-left" text-left v-if="chat.user !== nickname">
                <div class="left-bubble">
                  <span class="msg-name">{{chat.user}}</span>
                  <span class="msg-date">{{chat.sendDate}}</span>
                  <p text-wrap>{{chat.message}}</p>
                </div>
              </div>
            </div>
          </b-list-group-item>
        </b-list-group>
      </div>
      <footer class="sticky-footer">
        <b-form @submit="onSubmit">
          <b-input-group>
              <b-form-input id="message" v-model.trim="data.message" placeholder="Enter your message"></b-form-input>
              <b-button type="submit" variant="primary" :disabled="!data.message">Send</b-button>
          </b-input-group>
        </b-form>
      </footer>
    </b-col>
  </b-row>
</template>

Automatic vue-chat-scroll implemented in the div before the list of the chat message. Next, add the Vue.js script that contains the Firebase realtime-database reference to the chats collections, required variables, array, objects, and the method to submit a new message to the Firebase realtime-database and exit chat while submitting data to Firebase.

<script>

import firebase from '../Firebase'
import router from '../router'

export default {
  name: 'Chat',
  data () {
    return {
        roomid: this.$route.params.roomid,
        roomname: this.$route.params.roomname,
        nickname: this.$route.params.nickname,
        data: { type:'', nickname:'', message:'' },
        chats: [],
        errors: [],
        offStatus: false
    }
  },
  created () {
    let joinData = firebase.database().ref('chatrooms/'+this.roomid+'/chats').push();
    joinData.set({
      type: 'join',
      user: this.nickname,
      message: this.nickname+' has joined this room.',
      sendDate: Date()
    });
    this.data.message = '';
    firebase.database().ref('chatrooms/'+this.roomid+'/chats').on('value', (snapshot) => {
      this.chats = [];
      snapshot.forEach((doc) => {
        let item = doc.val()
        item.key = doc.key
        this.chats.push(item)
      });
    });
  },
  methods: {
    onSubmit (evt) {
        evt.preventDefault()

        let newData = firebase.database().ref('chatrooms/'+this.roomid+'/chats').push();
        newData.set({
            type: 'newmsg',
            user: this.nickname,
            message: this.data.message,
            sendDate: Date()
        });
        this.data.message = '';
    },
    exitChat () {
      let exitData = firebase.database().ref('chatrooms/'+this.roomid+'/chats').push()
      exitData.set({
        type: 'exit',
        user: this.nickname,
        message: this.nickname+' has exited this room.',
        sendDate: Date()
      })

      this.offStatus = true
      router.go(-1)
    }
  }
}
</script>

To make the chatbox more realistic view, add these CSS style codes.

<style>
  .chat-box {
    height: 500px;
    width: 100%;
    overflow: scroll;
  }
  .chat-item {
    border: none;
  }
  .chat-status {
    min-height: 49px;
  }
  .chat-status .chat-date {
    display: block;
    font-size: 10px;
    font-style: italic;
    color: #999;
    height: 15px;
    left: 10%;
    right:10%;
  }
  .chat-status .chat-content-center {
    padding: 5px 10px;
    background-color: #e1e1f7;
    border-radius: 6px;
    font-size: 12px;
    color: #555;
    height: 34px;
    left: 10%;
    right:10%;
  }
  .chat-message {
    width: 80%;
    min-height: 40px;
  }
  .chat-message .right-bubble {
    position: relative;
    background: #dcf8c6;
    border-top-left-radius: .4em;
    border-bottom-left-radius: .4em;
    border-bottom-right-radius: .4em;
    padding: 5px 10px 10px;
    left: 15%;
  }
  .chat-message .right-bubble span.msg-name {
    font-size: 12px;
    font-weight: bold;
    color: green;
    display: block;
  }
  .chat-message .right-bubble span.msg-date {
    font-size: 10px;
    display: block;
  }
  .chat-message .right-bubble:after {
    content: '';
    position: absolute;
    right: 0;
    top: 0;
    width: 0;
    height: 0;
    border: 27px solid transparent;
    border-left-color: #dcf8c6;
    border-right: 0;
    border-top: 0;
    margin-top: -0.5px;
    margin-right: -27px;
  }
  .chat-message .left-bubble {
    position: relative;
    background: #efefef;
    border-top-right-radius: .4em;
    border-bottom-left-radius: .4em;
    border-bottom-right-radius: .4em;
    padding: 5px 10px 10px;
    left: 5%;
  }
  .chat-message .left-bubble span.msg-name {
    font-size: 12px;
    font-weight: bold;
    color: blue;
    display: block;
  }
  .chat-message .left-bubble span.msg-date {
    font-size: 10px;
    display: block;
  }
  .chat-message .left-bubble:after {
    content: '';
    position: absolute;
    left: 0;
    top: 0;
    width: 0;
    height: 0;
    border: 27px solid transparent;
    border-right-color: #efefef;
    border-left: 0;
    border-top: 0;
    margin-top: -0.5px;
    margin-left: -27px;
  }
  footer.sticky-footer {
    position: fixed;
    bottom: 0;
    left: 0;
    width: 100%;
    padding: 10px;
    background-color: #ffffff;
    border-top: solid 1px #efefef;
  }
</style>


Run the Vue.js Firebase Realtime Chat Web App

Running the Vue.js and Firebase realtime chat web app is very simple. Just type this command in your terminal.

npm start serve

And here it is, you can test the realtime chat web app in your multiple machine or browser. You can watch this demo to find out how it works with multiple browsers.

That it's, the Vue.js Firebase Realtime Chat Web App tutorial. You can check the full source code from our GitHub.

That just the basic. If you need more deep learning about MEVN Stack, Vue.js or related you can take the following cheap course:

Thanks!

Loading…