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, 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 -vcommand to verify if you have the docker desktop installed); if not, install it from here. - An Appwrite instance running on your computer. Check out the documentation to create a local Appwrite instance. You can also install using digital ocean or 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.
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:
- Go to your
AppwriteConsole. - Click on Create Project and give your project a name.
- On the left side of the dashboard, click on Database and create a database.
- Click on the Add Collection button. This action redirects us to a Permissions page.
- At the Collection level, assign Read and Write Access with role:all.
- On the right of your Permissions page, copy the Collection ID, which you would need to perform operations on documents in this collection.
- Next, go to the
attributestab to create the properties you want a document to have. - Click on Add Attribute and then New String Attribute. Give it an ID called message and a Size of your choice.
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.
<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:
...
<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:
...
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.
...
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:
...
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:
- First, empty the notifications array. Then, you use Appwrite’s
listDocumentsmethod with yourCOLLECTION_IDto get all the documents. - 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:
async createDocument() {
try {
await database.createDocument('[COLLECTION_ID]', 'unique()', {
message: 'Welcome!',
});
this.listDocuments();
} catch (error) {
console.log(error);
}
},
This method does the following:
- The Appwrite
createDocumentmethod takes in the collection ID and the document payload to create a new document. Theunique()param generates a random document ID. - Calls the
listDocumentsmethod. - 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:
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:
- Checks if the
notificationsarray length is greater than zero. If it is, it gets the last document ID in the array and stores it in adocumentIDvariable. If the notifications array length is less than zero, the method shows an alert that the Database is empty. - Deletes the document using the Appwrite
deleteDocument()method. ThisdeleteDocumentmethod receives a collection ID and the document ID parameter. - Calls the
listDocumentsfunction. - Logs an error if deleting the document fails.
After following all these steps, your App.vue file should look like this:
<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:
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:
/** @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:
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:
watch: {
message: function (message) {
this.toast.show({
type: 'success',
message,
timeout: 2,
});
},
},
The final App.vue final should look like this:
<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:
Conclusion
This article showed you how Appwrite's real-time feature creates notifications in Nuxt3.



Top comments (1)
Go to your Appwrite Console.link is not working