How to Add Real-Time In-App Notifications in Nuxt3
Tags: appwrite, database, realtime, nuxt3
Published: 2022-10-04 10:45:37

---
title: How to Add Real-Time In-App Notifications in Nuxt3
published: true
description: 
tags: #appwrite #database #realtime #nuxt3
cover_image: https://res.cloudinary.com/chukwutosin/image/upload/v1664880659/IMG_4591_ywczap.png
# Use a ratio of 100:42 for best results.
---

Real-time notifications help users know when a change occurs in your app. You can implement real-time notifications in different ways.

This article teaches you how to implement notifications using [Appwrite](https://appwrite.io/?utm_source=hackmamba&utm_medium=hackmamba-blog), an open-source backend server, and Nuxt3, a hybrid vue framework.

## Repository
https://github.com/folucode/real-time-appwrite-nuxt3

## Prerequisites
- Basic understanding of CSS, JavaScript, and Nuxt.js.
- Docker Desktop installed on your computer (run the `docker -v` command to verify if you have the docker desktop installed); if not, install it from [here](https://www.docker.com/products/docker-desktop/).
- An Appwrite instance running on your computer. Check out the [documentation](https://appwrite.io/docs?utm_source=hackmamba&utm_medium=blog&utm_campaign=hackmamba) to create a local Appwrite instance. You can also install using [digital ocean](https://docs.digitalocean.com/products/marketplace/catalog/appwrite/) or [gitpod](https://www.gitpod.io/guides/appwrite-and-gitpod).

## Setting up Nuxt3

Run the command below to set up a Nuxt3 app:


    npx nuxi init appwrite-nuxt-app

Change directory:


    cd appwrite-nuxt-app

Install the dependencies:


    npm install

Now you'll be able to start a Nuxt3 development server with this command:


    npm run dev 

A browser window will automatically open at [http://localhost:3000](http://localhost:3000/).

Also, install these dependencies below as you will need them later in the course of this tutorial:


    npm install @nuxtjs/tailwindcss @tailvue/nuxt @iconify/vue appwrite --save
## Setting up Appwrite Database

Follow the instructions below to create the Database:

1. Go to your `Appwrite` [Console](http://localhost/console). 
2. Click on Create Project and give your project a name.
3. On the left side of the dashboard, click on Database and create a database.
4. Click on the **Add Collection** button. This action redirects us to a **Permissions** page.
5. At the **Collection level,** assign **Read** and **Write Access** with **role:all**. 


![AppWrite dashboard](https://paper-attachments.dropbox.com/s_2159BF3A474A99191FE34C7AAFCC4D90DCDE0B381CEEF8564F73F3F95BFA6945_1648376544970_Screenshot+63.png)



6. On the right of your **Permissions** page, copy the **Collection ID**, which you would need to perform operations on documents in this collection.
7. Next, go to the `attributes` tab to create the properties you want a document to have. 
8. Click on **Add Attribute** and then **New String Attribute**. Give it an ID called **message** and a **Size** of your choice.


![AppWrite dashboard](https://paper-attachments.dropbox.com/s_2159BF3A474A99191FE34C7AAFCC4D90DCDE0B381CEEF8564F73F3F95BFA6945_1648376497943_Screenshot+61.png)

## Creating the Application

Open `App.vue`, located at the root of the project folder, and replace the content with the code below. It is a template with two buttons referencing two methods you would create later. 

```javascript
<template>
      <div>
        <button
          type="button"
          class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
          @click="createDocument"
        >
          Create Document
        </button>
        <button
          type="button"
          class="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded"
          @click="deleteDocument"
        >
          Delete Document
        </button>
      </div>
</template>
```

Open a script tag in the same file and then import and initialize the `Appwrite` modules like so:

```javascript
    ...
    
    <script>
    import { Client, Account, Databases } from 'appwrite';
    
    const client = new Client();
    client
      .setEndpoint('http://localhost/v1') // Your Appwrite Endpoint
      .setProject('[PROJECT_ID]');
    
    const account = new Account(client);
    const database = new Databases(client, '[DATABASE_ID]');
    </script>
```
You can get the  **`PROJECT_ID`** and **`DATABASE_ID`** from your Appwrite console.

## Interacting with the Database

Only signed-in users can interact with the Appwrite database but you can create an anonymous session as a workaround for this.

In the same `App.vue` file, you can create an anonymous session using the method below. Add the code in the script tag, just below the initialization of the `Appwrite` modules:

```javascript
    ...
    
    account.createAnonymousSession().then(
      (response) => {
        console.log(response);
      },
      (error) => {
        console.log(error);
      }
    );
    
    </script>
```

## Setting up a Realtime Connection

In the `App.vue` file, export a default object. The data `method` returns an object with a `message` property and gives it a 'Welcome!' value. 

In the `mounted` method, check to make sure there is an active user session. If so, set up a real-time connection with `Appwrite` by subscribing to the documents channel. 

In the callback, assign the `message` variable a new value containing the timestamp of the database event.

```javascript
    ...
    
    export default {
      data() {
        return {
          message: 'Welcome!',
        };
      },
      mounted() {
        if (account.get !== null) {
          try {
            client.subscribe('documents', (response) => {
              this.message = `This event was called at ${response.timestamp}`;
            });
          } catch (error) {
            console.log(error, 'error');
          }
        }
      },
    };
    </script>
```
## Listing the Documents

In the current file, add a new property called `notifications` and give it a value of an empty array. In the Nuxt.js `methods` object, define a new method called `listDocuments` and paste the code below in it:

```javascript
    ...
    export default {
      data() {
        return {
          message: 'Welcome!',
          notifications: [],
        };
      },
      methods: {
        async listDocuments() {
          try {
            this.notifications = [];
            let response = await database.listDocuments('[COLLECTION_ID]');
            response.documents.map((document) =>
              this.notifications.push(document.$id)
            );
            console.log(this.notifications);
          } catch (error) {
            console.log(error);
          }
      },
      mounted() {
        ...
    </script>
```
This method does the following:

1.  First, empty the notifications array. Then, you use Appwrite’s `listDocuments` method with your `COLLECTION_ID` to get all the documents.
2. Map through the documents, push them into the notifications array, and log them to the console.

## Creating new Documents

Create a new method called `createDocument` just below the `listDocuments` method and paste the code below into it:

```javascript
    async createDocument() {
      try {
        await database.createDocument('[COLLECTION_ID]', 'unique()', {
          message: 'Welcome!',
        });
        this.listDocuments();
      } catch (error) {
        console.log(error);
      }
    },
```
This method does the following:

1. The Appwrite `createDocument` method takes in the collection ID and the document payload to create a new document. The `unique()` param generates a random document ID.
2. Calls the `listDocuments` method.
3. Logs an error if creating the document fails.

## Deleting Documents in the Collection

Create a new method called `deleteDocument` and paste the code below into it:

```javascript
    async deleteDocument() {
      if (this.notifications.length > 0) {
        try {
          let documentID = this.notifications[this.notifications.length - 1];
          await database.deleteDocument('[COLLECTION_ID]', documentID);
          this.listDocuments();
        } catch (error) {
          console.log(error);
        }
      } else {
        alert('database is empty');
      }
    },
```
The `deleteDocument` function does the following:

1. Checks if the `notifications` array length is greater than zero. If it is, it gets the last document ID in the array and stores it in a `documentID` variable. If the notifications array length is less than zero, the method shows an alert that the Database is empty.
2. Deletes the document using the Appwrite `deleteDocument()` method. This `deleteDocument` method receives a collection ID and the document ID parameter.
3. Calls the `listDocuments` function.
4. Logs an error if deleting the document fails.

After following all these steps, your `App.vue` file should look like this:

```javascript
    <template>
      <div>
        <button
          type="button"
          class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
          @click="createDocument"
        >
          Create Document
        </button>
        <button
          type="button"
          class="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded"
          @click="deleteDocument"
        >
          Delete Document
        </button>
      </div>
    </template>
    
    <script>
    import { Client, Account, Databases } from 'appwrite';
    const client = new Client();
    client
      .setEndpoint('http://localhost/v1') // Your Appwrite Endpoint
      .setProject('[PROJECT_ID]');
    
    const account = new Account(client);
    const database = new Databases(client, '[DATABASE_ID]');
    
    account.createAnonymousSession().then(
      (response) => {
        console.log(response);
      },
      (error) => {
        console.log(error);
      }
    );
    
    export default {
      data() {
        return {
          message: 'Welcome!',
          notifications: [],
        };
      },
      methods: {
        async listDocuments() {
          try {
            this.notifications = [];
            let response = await database.listDocuments('[COLLECTION_ID]');
            response.documents.map((document) =>
              this.notifications.push(document.$id)
            );
            console.log(this.notifications);
          } catch (error) {
            console.log(error);
          }
        },
        async createDocument() {
          try {
            await database.createDocument('[COLLECTION_ID]', 'unique()', {
              message: 'Welcome!',
            });
            this.listDocuments();
          } catch (error) {
            console.log(error);
          }
        },
        async deleteDocument() {
          if (this.notifications.length > 0) {
            try {
              let documentID = this.notifications[this.notifications.length - 1];
              await database.deleteDocument('[COLLECTION_ID]', documentID);
              this.listDocuments();
            } catch (error) {
              console.log(error);
            }
          } else {
            alert('database is empty');
          }
        },
      },
      mounted() {
        if (account.get !== null) {
          try {
            client.subscribe('documents', (response) => {
              this.message = `This event was called at ${response.timestamp}`;
            });
          } catch (error) {
            console.log(error, 'error');
          }
        }
      },
    };
    </script>
  ```  
## Creating the Notifications

In the `nuxt.config.ts`, replace the contents with the code below:

```javascript
    import { defineNuxtConfig } from 'nuxt';
    
    // https://v3.nuxtjs.org/api/configuration/nuxt.config
    export default defineNuxtConfig({
      meta: [{ name: 'description', content: 'My Appwrite site.' }],
      modules: ['@nuxtjs/tailwindcss', '@tailvue/nuxt'],
    });
 ```

`'@nuxtjs/tailwindcss'` and `'@tailvue/nuxt'` are the packages you installed at the beginning of this article. You'll use them to create the toast notifications.

Create a new file in the project root called `tailwind.config.js` and paste the code below into it:

```javascript
    /** @type {import('tailwindcss').Config} */
    module.exports = {
      content: ['node_modules/tailvue/dist/tailvue.es.js'],
      theme: {
        extend: {},
      },
      plugins: [],
    };
```
The toast package uses `tailwindcss`*.* 

## Showing the Notifications

First, add a new property in the `data`, return the object called `toast` and give it the value of an empty string. Destructure `$toast` from the `useNuxtApp` in the `mounted` method and assign it to the `**toast**` ****property you added to the `data` method:

```javascript
    mounted() {
        const { $toast } = useNuxtApp();
        this.toast = $toast;
        ...
      },
```
In a `watch` method which Nuxt.js provides, watch for changes on the `message` property and then show the new message in a toast:
```javascript

    watch: {
      message: function (message) {
        this.toast.show({
          type: 'success',
          message,
          timeout: 2,
        });
      },
    },
```
The final `App.vue` final should look like this:

```javascript
    <template>
      <div>
        <button
          type="button"
          class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
          @click="createDocument"
        >
          Create Document
        </button>
        <button
          type="button"
          class="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded"
          @click="deleteDocument"
        >
          Delete Document
        </button>
      </div>
    </template>
    
    <script>
    import { Client, Account, Databases } from 'appwrite';
    const client = new Client();
    client
      .setEndpoint('http://localhost/v1') // Your Appwrite Endpoint
      .setProject('[PROJECT_ID]');
    
    const account = new Account(client);
    const database = new Databases(client, '[DATABASE_ID]');
    
    account.createAnonymousSession().then(
      (response) => {
        console.log(response);
      },
      (error) => {
        console.log(error);
      }
    );
    
    export default {
      data() {
        return {
          message: 'Welcome!',
          notifications: [],
          toast: '',
        };
      },
      methods: {
        async listDocuments() {
          try {
            this.notifications = [];
            let response = await database.listDocuments('[COLLECTION_ID]');
            response.documents.map((document) =>
              this.notifications.push(document.$id)
            );
            console.log(this.notifications);
          } catch (error) {
            console.log(error);
          }
        },
        async createDocument() {
          try {
            await database.createDocument('[COLLECTION_ID]', 'unique()', {
              message: 'Welcome!',
            });
            this.listDocuments();
          } catch (error) {
            console.log(error);
          }
        },
        async deleteDocument() {
          if (this.notifications.length > 0) {
            try {
              let documentID = this.notifications[this.notifications.length - 1];
              await database.deleteDocument('[COLLECTION_ID]', documentID);
              this.listDocuments();
            } catch (error) {
              console.log(error);
            }
          } else {
            alert('database is empty');
          }
        },
      },
      mounted() {
        const { $toast } = useNuxtApp();
        this.toast = $toast;
    
        if (account.get !== null) {
          try {
            client.subscribe('documents', (response) => {
              this.message = `This event was called at ${response.timestamp}`;
            });
          } catch (error) {
            console.log(error, 'error');
          }
        }
      },
      watch: {
        message: function (message) {
          this.toast.show({
            type: 'success',
            message,
            timeout: 2,
          });
        },
      },
    };
    </script>
```

Here is what the app should look like:

![final app look](https://paper-attachments.dropbox.com/s_7B5B97E2663C656EB0C203459C4F44BA8F568854D8EA43AEABEBE15905C05381_1661342771613_realtime_appwrite_AdobeExpress.gif)

## Conclusion

This article showed you how Appwrite's real-time feature creates notifications in Nuxt3.

## Resources
- [Appwrite’s documentation](https://appwrite.io/docs/installation)
- [Nuxt3 Documentation](https://v3.nuxtjs.org/getting-started/quick-start)
- [Tailwindcss Documentation](https://tailwindcss.com/docs/guides/nuxtjs)
- [NuxtTailwind Documentation](https://tailwindcss.nuxtjs.org/getting-started/setup/)
- [Tailvue Documentation](https://github.com/fumeapp/tailvue)