Build your own CMS using low-code
Tags: javascript, tooljet, mongodb, nextjs
Published: 2023-03-28 06:21:33

> In this tutorial, We will build CMS(Content Management System) using the ToolJet which is a lowcode application development platform. The CMS can be used to perform CRUD operations to the MongoDB which is used as the database for the NextJS application.

#### Table of Contents
- [Overview](#overview)
- [Prerequisites](#prerequisites)
- [Setting up the database](#setting-up-the-database)
- [Connecting MongoDB to ToolJet](#connecting-mongodb-to-tooljet)
- [Building the UI, Queries and connecting them](#build-the-ui-of-the-cms-app)
- [Connecting to NextJS app](#connecting-to-nextjs-app)

---

## Overview
A **content management system (CMS)** is an application used for managing content creation and modification, usually articles and blog posts containing images and videos. WordPress CMS is one of the popular CMS. CMSs make it easy to perform CRUD operations (create, read, update, and delete) without coding knowledge.
[ToolJet](https://tooljet.com) is a free and [open-source](https://github.com/tooljet/tooljet) low-code app development platform that allows you to build applications quickly and has more than 30+ datasources including [MongoDB](https://www.mongodb.com/) that will let you seamlessly perform operations on your database. You can create a free account on ToolJet Cloud or run it on your [local machine](https://docs.tooljet.com/docs/setup/).
Many developers use databases like MongoDB and frameworks like NextJS for their full-stack web applications. Sometimes performing CRUD operations can be time taking for developers and can be hectic for someone who is not familiar with running database queries. In this tutorial, we will build an app using ToolJet that will solve these problems. The CMS app will be connected to the MongoDB database to perform CRUD operation, and the changes will be reflected on the [NextJS](https://nextjs.org/) application.

![appui](https://blog.tooljet.com/content/images/2023/02/pika-1677498610481-1x.jpeg)

**Want to use the app without going through the complete tutorial?**

- Import the exported application JSON file to your ToolJet account. Here's the [file](https://blog.tooljet.com/content/files/2023/02/cms_mongo-export-1677491297947.json).
- Once imported the application, you'll need to connect the MongoDB datasource using host details or **connection string**.

### Prerequisites

1. **MongoDB database**: You can set up the MongoDB database locally or use [Atlas](https://www.mongodb.com/atlas/database). For this tutorial, we are going to use Atlas.
2. **ToolJet** (https://github.com/ToolJet/ToolJet): A free and open-source low-code platform that allows you to build applications quickly. Sign up [here](https://tooljet.com/).
3. **[NextJS app](https://nextjs.org/)**: We will learn how to build one sample app using the command line later in this tutorial.

---

## Setting up the database
Once you have created an account on MongoDB Atlas, you'll be asked to enter the `username` and `password` for your database (not the same as what you use to log into the MongoDB cloud). Once done, you'll be redirected to your project's database deployment, where you can create/manage Clusters. You can create a new Cluster and choose a configuration according to your preference.

![mongo1](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-02-at-9.40.15-AM.png)

As you can see in the screenshot above, we have  `Cluster0` deployed. Go to the `browse collections` and create a new database `cms` with three collections `posts`, `authors`, and `tags`.

- `posts`- this collection will store all the blog posts information
- `authors`- this collection will store information on all the authors
- `tags` - this collection will store the tags

Let's insert at least one sample document in each collection. For posts:

- `_id`: the object id will be generated by MongoDB automatically.
- `title`: enter the title of the blog posts.
- `subtitle`: enter the subtitle
- `content`: enter the content/body of blog posts
- `cover`: enter the URL of the cover image
- `author_name`: enter the name of the author
- `tag_name`: enter the tag name
- `published_on`: enter the date in DD/MM/YYYY format
The data type of all the records should be **string**.

![object](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-02-at-10.08.21-AM.png)

Similarly, we will insert documents in authors and tags. For authors

- `_id`: the object id will be generated by MongoDB automatically.
- `author_name`: name of the author
- `author_email`: email of the author
- `author_image`: URL of author's headshot image

![authors](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-02-at-10.08.54-AM.png)

For `tags`:

- `_id`: the object id will be generated by MongoDB automatically.
- `tag_name`: name of the tag

Once you have inserted the sample documents in all three collections, we are good to go. Our database is ready.

Now, let's go to ToolJet and connect the database.

---

## Connecting MongoDB to ToolJet

Let's go to the **ToolJet dashboard** and create a **new app**. Once you click the **New App button**, an untitled app will open in the app builder. You can rename the app from the toolbar. On the left sidebar, you'll find the third option for adding or editing datasources.

![newapp](https://blog.tooljet.com/content/images/2023/03/Screenshot-2023-03-06-at-6.53.03-PM.png)

Click on the **+ add datasource** and a modal will pop up with a list of all the available datasources. Select **MongoDB** from the list and enter the credentials for connecting.

![datasource](https://blog.tooljet.com/content/images/2023/03/Screenshot-2023-03-06-at-6.59.59-PM.png)

For this tutorial, we are using MongoDB Atlas to connect to MongoDB datasource using the **connection string**.

![creds](https://blog.tooljet.com/content/images/2023/03/Screenshot-2023-03-06-at-7.03.44-PM.png)

You can find your connection string by going to the MongoDB Atlas dashboard. Go to `Database Deployments` on the Atlas and click on the **Connect** button next to the cluster name ( **Cluster0** in our case). A connection dialog will pop up to choose the method by which you want to connect, click on the second option - **Connect your application**. Once you click on the second option, you'll get the connection string - click on the copy button next to it to copy the string.

![mongodash](https://blog.tooljet.com/content/images/2023/03/Screenshot-2023-03-06-at-7.05.39-PM.png)

The string that you'll copy will be like this `mongodb+srv://testusername:<password>@cluster0.nc8nial.mongodb.net/?retryWrites=true&w=majority` where `testusername` is the database username that we created before, we will need to replace `<password>` with the password that we created for this database and then remove everything after `.net/` and add your database name - in our case, the name of the database is `cms`.

So, the actual connection string will be: `mongodb+srv://testusername:fakepassword@cluster0.nc8nial.mongodb.net/cms`

Copy-paste the connection string on the ToolJet and click on the test connection button to test the connection before saving the datasource once the connection is **successful** then save the datasource.

![success](https://blog.tooljet.com/content/images/2023/03/Screenshot-2023-03-06-at-7.10.50-PM.png)

Now, that we have successfully connected the MongoDB database, we can build the user interface of the CMS app.

---

## Build the UI of the CMS app

Let's start building the UI of the CMS application using ToolJet, which is a low-code application development platform.

The CMS application is a [multi-page application](https://docs.tooljet.com/docs/tutorial/pages) that will have the following 5 pages:

### All Posts

![allpostsimage](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-16-at-4.05.35-PM.png)

### New Post

![newpostimage](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-16-at-4.06.08-PM.png)

### Edit Post

![editpost](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-16-at-4.06.25-PM.png)

### View Post

![viewpost](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-16-at-4.07.04-PM.png)

### Authors and Tags

![allpostsimage](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-16-at-4.07.54-PM.png)

In the previous section, we connected the MongoDB datasource to a new application. Now, all we need to do is build the UI and then create queries and connect them with the UI.

The very first thing we are going to do is create Pages in our application. We can find the Pages option on the left sidebar from where we can add the pages to the application. Let's add the following pages:

- **all_posts**
- **new_post**
- **edit_post**
- **view_post**
- **authors_tags**

![pages](https://blog.tooljet.com/content/images/2023/03/Screenshot-2023-03-16-at-5.37.41-PM.png)

> 💡 Before we begin with UI, it is recommended to learn about ToolJet's app builder: https://docs.tooljet.com/docs/app-builder/overview

### All Posts: UI
The All Posts page will show the list of all the blog posts. This is going to be the home page of the application, and from this page, we can navigate to other pages.

This page will use the listview component to show a list of blogs and buttons to navigate other pages. Let's build the UI:

- Let's drag a **container** on the **canvas** and increase its height to reach the bottom and its width to both sides. You can click on the handle of the container to edit its properties.
- Drag a text component and set its value to `<h1>All Posts</h1>`. Yes, we can use HTML tags inside the text component to format text value.
- Drag a divider below the text component.

![all_post_ui](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-16-at-4.40.57-PM.png)

- Now drag two **button** components above the right side of the divider and style the buttons.
- For the first button, we will set the button text to **New Post** and edit its **Styles**. Set the button color to `#14171a` , text color to `white/#ffffff`, loader color to `white`, border-radius to `2` , border color to `#14171a`
- Add an **Event Handler** to the **New Post** button, choose **switch page** action, and then select the `new_post` from the dropdown. Now, whenever the button is clicked `New Post` page of the application will be loaded.

![allpostui](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-16-at-4.47.56-PM.png)

- For the second button, we will set the button text to **Authors and Tags** and edit its **Styles**. Set the button color to `white/#ffffff` , text color to `#14171a`, loader color to `#14171a`, border-radius to `2` , border color to `#14171a`
- Add an **Event Handler** to the **Authors & Tags** button, choose **switch page** action, and select the `authors_tags` from the dropdown. Now, whenever the button is clicked `Authors & Tags` page of the application will be loaded.

![authortagss](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-16-at-4.55.03-PM.png)

- Now drag a **listview** component below the **divider**. Go to its **Styles** and set the border color to white.

![listview1](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-16-at-5.09.45-PM.png)

- Let's add **components** inside the listview. Remove the **image** component, and add **three text components** and **two buttons** as shown in the image below.

![listview2](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-16-at-6.17.46-PM.png)

- Currently, the listview looks very rough since we haven't styled the nested components (text and buttons) yet. To make it look better, we can add some styling to the components and some placeholder text until we create the query for the data to be loaded into the listview.
- Let's edit the properties and styles of the nested text components and buttons:
 - text1: Text = `Title of the blog` , Font weight = `Bold` , Font size = `16`
 - text2: Text = `By Author - 06/02/2023` , Font weight = `Lighter`
 - text3: Text = `Tag` , Font weight = `Lighter`
 - button1: Button text = 👁️ , Background color = `white` , Border radius = `2` , Border color = `#e2e4e4`
 - button2: `Button` text = ✏️ , Background color = `white` , Border radius = `2` , Border color = `#e2e4e4`

![listview3](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-16-at-6.44.07-PM.png)

- For the view/👁️ and edit/✏️ buttons inside listview, we need to add event handlers. On both buttons, we need to add an event handler for `set variable` event that creates a variable `selectedListViewIndex` and the variable value will be `{{listItem._id}}` - this value will be there once we create the query. Another event handler that we need to add is to switch the page, for the edit button link `edit_post` page and for the view button link `view_post` page.

![listview4](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-16-at-6.49.32-PM.png)

The UI of the All Posts page is almost finished, now let's go ahead and build the queries and connect to the UI.

### All Posts: Queries
Let's build the required query for loading the data on All Posts page. Since we are only loading the list of all the blogs from the database on the listview, we need to build a single query:

#### posts
- Go to the query panel at the bottom of the app builder, create a new MongoDB query, and name it as `posts`
- Select the **Find Many** **Operation** from the dropdown options and then enter the **Collection** name as `posts` which is the name of the collection in our `cms` db that we created in MongoDB Atlas
- From the **Advanced** section, toggle on the `Run query on application load?` option, and then **save** the query. This will execute the query every time the app is loaded.
- **Run** the query to trigger it, and we can check the data returned by the query from the inspector panel on the left sidebar.

![postsquery](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-17-at-10.04.59-AM.png)

#### authors

- Create a new MongoDB query, and name it as authors
- Select the `Find Many` **Operation** from the dropdown options and then enter the Collection name as `authors` which is the name of the **collection** in our cms db that we created in MongoDB Atlas
- From the **Advanced** section, toggle on the `Run query on application load?` option, and then **save** the query. This will execute the query every time the app is loaded.
- **Run** the query to trigger it and we can check the data returned by the query from the inspector panel on the left sidebar.

![authorsquery](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-17-at-10.34.03-AM.png)

#### tags

- Create a new MongoDB query, and name it as `tags`
- Select the `Find Many` **Operation** from the **dropdown** options and then enter the Collection name as `tags` which is the name of the **collection** in our cms db that we created in MongoDB Atlas
- From the **Advanced** section, toggle on the `Run query on application load?` option, and then save the query. This will execute the query every time the app is loaded.
- **Run** the query to trigger it and we can check the data returned by the query from the inspector panel on the left sidebar.

![tags query](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-17-at-10.34.20-AM.png)

### All Posts: Connecting queries data to UI

- Now, that we have the `posts`, `authors`, and `tags` data from the database, we can populate the listview component. Edit the properties of the ListView component and set the **List data** value to `{{queries.posts.data}}`.

![connectingui](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-17-at-10.09.39-AM.png)

- The rows will be added to the listview but the actual data won't show up because the components inside the listview currently hold the placeholder values. Let's remove the placeholder values from the components inside the ListView. Go to the text component whose value is `Title of the blog` and set its value to `{{listItem.title}}`

![uititle](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-17-at-10.13.19-AM.png)

- Set the value of the second text component to `By {{listItem.author_name}} -  {{listItem.published_on}}`
- Set the value of the third text component to `{{listItem.tag_name}}`

![uiauthor](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-17-at-10.39.28-AM.png)

We are finally done with the **All Posts** page, all we need to do now is build the UI of the remaining 4 pages and then connect the queries.

---

### New post: UI
The New Post page will be used to create a new blog post and insert it into the collection `posts`. Let's click on the **New Post** button on the top of the **All Post** page and switch to the `new_post` page as we have already added the event handler to the button.

This page will use the container component as the body and we will nest components like text, text-input, dropdown, etc. to create a form-like structure for getting the input from the users. Let's build the UI:

- We are going to build a UI similar to the UI that we build for the **All Posts** page. First, we will drag a container component onto the canvas and then we will use the text component for the Title of the page i.e `New Post` with a divider component below it.
- On the right side of the divider, we can simply copy and paste the `Authors & Tags` button from the All posts page and paste it into the New Post page. Change the button text to **< Back** and add the **event handler** to **switch the page** to `all_posts`

![dividerui](https://blog.tooljet.com/content/images/2023/03/Screenshot-2023-03-17-at-2.56.52-PM.png)

- Now we are going to drag components and build a form-like structure below the divider component.
 - We are going to drag a text component, set its value to Title, set Font weight to Bold, and Font Size to 16
 - We will copy-paste(using [keyboard shortcuts](https://docs.tooljet.com/docs/tutorial/keyboard-shortcuts)) the Title text component 5 more times and then change their text to Subtitle, Content, Cover Image, Author, and Tag, respectively.
- Now, we will place the following components next to the headings:
 - Title: text input component and set placeholder to Title
 - Subtitle: text input component and set placeholder to Subtitle
 - Content: text area component and set placeholder to Content
 - Cover Image: text input component and set placeholder to Cover Image
 - Author: dropdown component and set placeholder to Author
 - Tag: dropdown component and set placeholder to Tag
- Set the value of the border radius of all the input components to `{{2}}` to make them look better

![formui](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-17-at-2.59.11-PM.png)

- Our form is almost complete, now at the bottom of the page we will add a button. We will copy-paste the button from the **All Posts** page and change the button text to **Submit**. Remove the existing event handlers, and add an event handler to switch the page to `all_posts` . We will add another event handler once we create the query for submitting the form.

![formui2](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-17-at-3.10.49-PM.png)

The UI for creating a new blog post is ready, now let's create the query for inserting the form values into the database.

### New post: Queries

#### add_post

- Create a new MongoDB query, and name it as add_post
- Select the `Insert One` **Operation** from the dropdown options and then enter the **Collection** name as `posts` which is the name of the collection in our cms db that we created in MongoDB Atlas
- In the **Document** field, enter the following:
```js
{title: "{{components.textinput1.value}}", subtitle: "{{components.textinput2.value}}", content: "{{components.richtexteditor1.value}}", cover: "{{components.textinput3.value}}", author_name: "{{components.dropdown1.value}}", tag_name: "{{components.dropdown2.value}}", published_on: "{{moment().format("DD/MM/YYYY")}}" }
```

- In the code snippet above, we are **dynamically** getting values from the input components.
- Go to the bottom of the query manager and add the event handler to **run the query** on the **Query Success** event and select the posts query. Doing this will trigger the posts query every time this add_post query is successful or simple words whenever the user submits the blog then the list of the blogs will be refreshed on the front-end. Finally, **Save** the query.

![querymanager](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-17-at-4.38.48-PM.png)

#### New post: Connecting queries data to UI

On this page, all we need to do is connect the query that we created in the previous step to the submit button so that whenever the button gets clicked, the query for inserting the post is triggered and then the page switches to the home page i.e. All Posts page.

- Click on the handle of the **Submit** button, and go to the **Events** section under its properties.
- While building the UI we already added an **event handler** for **switching** the page to `all_posts`, now we need to add another event handler to **Run the query** on the **On Click** event -> Select the `add_post` query. Move the Run query event handler above the Switch Page event handler to ensure the query runs first and then the page switches to the home page.

![onclickui](https://blog.tooljet.com/content/images/2023/03/Screenshot-2023-03-17-at-5.02.37-PM.png)

### Edit post: UI

This page is going to be the clone of the New Post page; we will replace the Submit button with the update button and will add another button for deleting the selected post. Let's go!

- Let's go to the **New Post** page and select the container. Press `ctrl/cmnd+c`, go back to the **Edit Post** page and press `ctrl/cmnd+v`, doing this will clone the container entirely including the nested components from the New Post page.
- Change the Title from `New Post` to `Edit Post`
- Set the **default values** of the following input components:
 - Default Value for Title's text input : `{{queries.posts.data.filter(post => post._id == variables.selectedListViewIndex)[0].title}}`
 - Default Value for Subtitle's text input : `{{queries.posts.data.filter(post => post._id == variables.selectedListViewIndex)[0].subtitle}}`
 - Default Value for Content's text area : `{{queries.posts.data.filter(post => post._id == variables.selectedListViewIndex)[0].content}}`
 - Default Value for Cover Image's text input: `{{queries.posts.data.filter(post => post._id == variables.selectedListViewIndex)[0].cover}}`
 - Default Value for Author's dropdown component: `{{queries.posts.data.filter(post => post._id == variables.selectedListViewIndex)[0].author_name}}`
 - Option Value for Author's dropdown component: `{{queries.authors.data.map(i => i.author_name)}}`
 - Option Labels for Author's dropdown component: `{{queries.authors.data.map(i => i.author_name)}}`
 - Default Value for Tag's dropdown component: `{{queries.posts.data.filter(post => post._id == variables.selectedListViewIndex)[0].tag_name}}`
 - Option Value for Tag's dropdown component: `{{queries.tags.data.map(i => i.tag)}}`
 - Option Labels for Tag's dropdown component: `{{queries.tags.data.map(i => i.tag)}}`

![editpost](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-17-at-6.07.41-PM.png)

- Let's go to **Submit** button and change the button text to **Update**. We will keep both the event handlers as it is and will replace the query in the Run Query handler later once we build the query.
- Copy the **Back** button from the top and paste it below next to the **Update** button. Change the button text to **Delete**. We will add the event handler in the next section when we create the query. Go to the **Styles**, change the button text and border color to red.

![backui](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-17-at-6.11.57-PM.png)

The UI of the Edit Post section is finished. We also updated the default values of the components so that whenever a listItem is clicked from the homepage the details of the selected blog details get updated on the edit page field values.  

### Edit post: queries
#### delete_post

- Create a new query from the query panel, and name it `delete_post`
- Select the `Find one and delete` **Operation** from the dropdown options and then enter the **Collection** name as `posts`
- In the **Filter** field value enter:

```JavaScript
{"title":"{{queries.posts.data.filter(post => post._id == variables.selectedListViewIndex)[0].title}}"}
```

- Scroll to the bottom, add an event handler to **run the query** on the **Query Success** event and select the `posts` query and then **Save** the query.

![querysucces](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-17-at-6.45.23-PM.png)

#### update_post

- Create another MongoDB query from the query panel, and name it `update_post`
- Select the `Find one and update` **Operation** from the dropdown options and then enter the **Collection** name as `posts`
- In the **Filter** field value enter:
```JavaScript
{"title":"{{queries.posts.data.filter(post => post._id == variables.selectedListViewIndex)[0].title}}"}
```
- In the **Update** field value enter:

```JavaScript
{ $set: {title:"{{components.textinput1.value}}", subtitle:"{{components.textinput2.value}}", content:"{{components.richtexteditor1.value}}", cover:"{{components.textinput3.value}}", author_name:"{{components.dropdown1.value}}", tag_name:"{{components.dropdown2.value}}"} }
```
![js](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-17-at-6.49.22-PM.png)

- Scroll to the bottom, add an event handler to **run the query** on the **Query Success** event, and select the **posts** query and then **Save** the query.

![runthequery](https://blog.tooljet.com/content/images/2023/03/Screenshot-2023-03-17-at-6.51.20-PM.png)

### Edit post: Connecting queries data to UI

Now, all we need to do is update the event handlers on the Update and Delete buttons.

- Click on the **handle** of the **Delete** button to edit its **properties**. Go to **Events**, and change the query in the Run Query event to `delete_post`

![editpostconnnect](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-17-at-7.00.06-PM.png)

- Similarly, we will update the event handler of the **Update** button. Open its properties, go to Events, and change the query in the **Run Query** event to update_post

![runqueryui](https://blog.tooljet.com/content/images/2023/03/Screenshot-2023-03-17-at-7.00.36-PM.png)

### View post: UI
This page will be loaded when the 👁️/view button is clicked next to the item in the listview on the All Posts page. Let's build the UI:

- Go to the home page/All Posts page and click on the 👁️/view post button next to the list item to load the `view_post` page
- Once the `view_post` page is loaded, drag a **container** component onto the canvas. Expand the container completely both vertically and horizontally to fit the entire canvas.
- Go to either of the page `New Post` or `Edit Post`, copy the back button and paste it on the `view_post` page. Drag a **divider** component below the button.
![dragcontainer](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-20-at-2.36.32-PM.png)

- Now let's drag the following components and set their properties and styles:
 - text component for showing the Title: text = `{{queries.posts.data.filter(post => post._id == variables.selectedListViewIndex)[0].title}}` , font weight = bold, font size = 16
 -  text component for showing the Subtitle: text = `{{queries.posts.data.filter(post => post._id == variables.selectedListViewIndex)[0].subtitle}}` , font weight = bold, font size = 15
 -   text component for showing the Author: text = Author: `{{queries.posts.data.filter(post => post._id == variables.selectedListViewIndex)[0].author_name}}` , font weight = bold, font size = 14
 - image component for displaying the Cover Image: URL = `{{queries.posts.data.filter(post => post._id == variables.selectedListViewIndex)[0].cover}}`
 - text component for showing Content: text = `{{queries.posts.data.filter(post => post._id == variables.selectedListViewIndex)[0].content}}` , font weight = normal, font size = 14
![componentsvalues](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-20-at-3.15.51-PM.png)

### View post: Queries
This page doesn't requires any queries. The data on this page is loaded using the queries that we created previously.

### View post: Connecting queries data to UI
We have already connected the data while building the UI. We are using variables that we created previously to filter the data according the clicked list item.
For ex: for loading the Title of the selected list view item we have set the value:
```js
{{queries.posts.data.filter(post => post._id == variables.selectedListViewIndex)[0].title}}
```

### Authors & Tags: UI
We are finally at the last page of the application. In this page we are going to display the list of all the author and all the tags. From this page we can perform CRUD operations on `authors` and `tags` collection in database. Let's build the UI:

- Go to the homepage/All Posts page of the application and click on the `Authors & Tags` button on the page, this will redirect you to the `authors_tags` page
- Drag a **container** onto the canvas and resize(both vertically and horizontally) it to fit the canvas. Copy the **back button** from any of the other pages and paste it on the top-right of this page
- Let's add two text components use html tags to make them into Title: **Authors, Tags**
- Add two **divider** components below the titles and two tables respectively.
![authorsandtagsui](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-20-at-3.48.00-PM.png)
- Now, we will be adding two buttons, one for adding the authors into the database and the other for adding tags into the database. We can copy the New Post button from the home page to keep the styling same. Remove the event handlers and change the button text to **+Add**.
![add](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-20-at-3.50.58-PM.png)

- Drag **three modals** somewhere below the container. These modals will be shown when the following buttons are clicked: **+Add** button for **Authors**, **+Add** button for **tags**, and **View action** button on **Authors** table.
- **Toggle off** the `Use default trigger button` for all the three modals.
![modalui](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-20-at-4.35.06-PM.png)

- Go to the **properties** of **+Add** button for **Authors**, add an **event handler** to show the **modal1**. Click on the button to show the **modal1**. Once the modal loads click somewhere outside the modal, then drag the components from the components library onto the modal:
 - 3 text components: Author Name, Author Email, and Author Image
 - 3 text input components : name, email, image URL
 - A button component for triggering the query that we will create in the next section, set the button text to `Add`

![modal1ui](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-20-at-4.50.05-PM.png)

- Just like the **+Add** button for Authors, we are going to add an event handler on the +Add button for tags to trigger **modal2**, open the modal and add the following components inside the modal:
 - 1 text input components: **Tag**
 - A button component for triggering the queries that we will create in the next section, set the button text to **Add Tag**

![modal2](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-20-at-5.01.38-PM.png)

- Go to the **Authors** Table, add two **Action buttons:  View and Remove**. On View action button, we will add an event handler to show the **modal3** and the Remove action button will trigger the query that will remove the selected author from the collection.
![modal3](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-20-at-5.08.38-PM.png)

- Click on the **View** button to show the modal, add components inside the modal3 just like we have added components in the previous 2 modals:
 - 2 text components: text = `{{components.table1.selectedRow.author_name}}` & `{{components.table1.selectedRow.author_email}}`, keep the font weight = bold for the first text component.
 - 1 image component to display the author image: `{{components.table1.selectedRow.author_image}}`  
- Go to the **Tags** Table, and add one **Action button:  Delete**. This action button will trigger the query that will remove the selected tag from the collection.

![tagstable](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-20-at-5.09.11-PM-1.png)

### Authors & Tags: Queries
#### add_authors

- Create a new MongoDB query, name it `add_author`, select `insert one` from the **operations** dropdown, and enter `authors` in the collection field.
- In the **Document** field, enter:
```js
{author_name: "{{components.textinput1.value}}", author_email: "{{components.textinput2.value}}",author_image: "{{components.textinput3.value}}" }
```
- Go to the bottom, and add an **event handler** to run **authors** query on **Query Success Event**. Finally, **Save** the query.

![querysuccessevent](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-20-at-6.06.51-PM.png)

#### add_tags

- Create a new MongoDB query, name it `add_tag`, select `insert one` from the **operations** dropdown, and enter `tags` in the collection field.
- In the Document field, enter:
```js
{tag:"{{components.textinput4.value}}"}
```
- Go to the bottom, and add an **event handler** to run tags query on **Query Success** Event. Finally, **Save** the query.
![savethequery](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-20-at-6.11.23-PM.png)

#### delete_author

- Create a new MongoDB query, name it `delete_author`, select `delete one` from the **operations** dropdown, and enter `authors` in the **collection** field.
- In the **Filter** field, enter:
```js
{"author_name":"{{components.table1.selectedRow.author_name}}"}
```
- Go to the bottom, and add an event handler to run `authors` query on `Query Success` Event. Finally, **Save** the query.
![deleteauthorquery](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-20-at-6.26.48-PM.png)

#### delete_tag

- Create a new MongoDB query, name it `delete_tag`, select `delete one` from the **operations** dropdown, and enter `tags` in the **collection** field.
- In the **Filter** field, enter:
```js
{"tag":"{{components.table2.selectedRow.tag}}"}
```
- Go to the bottom, and add an **event handler** to run `authors` query on **Query Success** Event. Finally, **Save** the query.
![deletetagquery](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-20-at-6.28.03-PM.png)

### Authors & Tags: Connecting queries data to UI
Let's connect the queries to the table components to display the data and the button components for triggering the insert and delete queries:

- Go to the **Author's** table, edit its **properties**, and set **table data** to `{{queries.authors.data}}` . The columns will be **auto-populated**. Enable the **highlight selected row** from the options and set the **loading state** of the table to `{{queries.delete_author.isLoading || queries.authors.isLoading}}`
- Edit **Remove** action button and add the **event handler** to run the `delete_author` query. This will remove the author from the database whenever the action button is clicked.

![connectingauthorstags](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-20-at-6.37.06-PM.png)

- Click on the **+Add** Authors button to show the modal, inside modal, there is a **Add button** for submitting the form. Add the following event handlers to this button:
 - **1st event handler** to run the query: `add_author`
 - the **next 3 event handlers** to `control the component`. Components will be the three text inputs that are there in the modal and the Action will be Clear . Adding these event handlers will clear the form as soon as the `add_author` query is triggered.
 - **last** event handler for **closing the modal**.

![eventhandlers](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-20-at-6.43.27-PM.png)

- Now, we are going to add the event handlers to +Add button for the Tags:
 - **1st event handler** to run the query: `add_tag`
 - the **next event handler** to **control the component**. Select the text input component that is there in the form and set the Action to `Clear` .
 - **last** event handler for **closing the modal**.

![closingthemodal](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-20-at-6.46.07-PM.png)

- Finally, go to the **Tags** table, and set the **table data** to `{{queries.tags.data}}` . The columns will be **auto-populated**. Enable the **highlight selected row** from the options and set the **loading state** of the table to `{{queries.delete_tag.isLoading || queries.tag.isLoading}}`
- Edit **delete** action button and add the event handler to run the `delete_tag` query.

![loadingstate](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-20-at-6.48.01-PM.png)

---

## Connecting to NextJS app
Using the connection string, we can connect the MongoDB Atlas database to any NextJS app. In this section, we will locally set up a NextJS application and then connect it to the MongoDB database to load the data on the front end.

### Requirements:

- **MongoDB Atlas database**
- **NodeJS 12+**
- **npm and npx**
- **Vercel (Optional if you want to deploy your NextJS app)**

### Building NextJS app

Go to the terminal, and enter the following command:
```bash
npx create-next-app --example with-mongodb nextblog
```

We are using the `npx create-next-app` command and are passing the `--example with-mongodb` parameter which will tell `create-next-app` to bootstrap our app with the MongoDB integration example. Finally, `nextblog` is the name of our application.

Executing this command will take a couple of seconds to download and install all the npm dependencies, but once they're downloaded and installed, navigate to your project directory by running:
```bash
cd nextblog
```
Install all the npm dependencies by running:

```bash
npm install
```
Now, let's start up our application. To start our Next.js app, execute:
```bash
npm run dev
```
Once the app is built successfully, we can navigate to `localhost:3000` to see our app live in action.

![localhost1](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-21-at-4.25.45-AM.png)

We will get an error similar to the one in the screenshot above because the app is built but we haven't connected our MongoDB database yet to the application. So let's do that.

### Connecting MongoDB

- On the `nextblog` directory, we can find the `env.local.example` file. We can rename the file to `env.local` and then edit it.
- In this file, we will need to enter the value for `MONGODB_URI` and `MONGODB_DB` variable. `MONGODB_URI` is nothing but the connection string till / and `MONGODB_DB` will be the name of the database. Go to the beginning of the tutorial to learn how we can obtain the connection string from the Atlas. The `env.local` file will look like this:
![envfile](https://blog.tooljet.com/content/images/2023/03/Screenshot-2023-03-21-at-4.34.44-AM-1.png)

- As soon as you save these environment variables, go to the browser and you'll see that the error is gone and `with-mongodb` Next.js app welcome page is loaded.
![welcome](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-21-at-4.39.58-AM.png)

### Querying MongoDB with Next.js
The first example we'll look at is building and exposing an API endpoint in our Next.js application. To create a new `API` endpoint route, we will first need to create an api directory in our `pages` directory, and then every file we create in this `api` directory will be treated as an individual API endpoint.

Let's go ahead and create the `api` directory and a new file in this `directory` called `posts.js`. This endpoint will return a list of all the blog posts from our `posts` collection in the MongoDB database. The implementation for this route is as follows:
```JavaScript
import { connectToDatabase } from "../../lib/mongodb";


export default async function handler(req, res){
    const {db} = await connectToDatabase();

    const data = await db.collection("posts").find({}).toArray();

    res.json(data);
}
```
Go to the `lib/mongodb.ts` file and update the existing code to the following code:
```JavaScript
import { MongoClient } from 'mongodb'

const { MONGODB_URI, MONGODB_DB } = process.env

if (!MONGODB_URI) {
  throw new Error(
    'Please define the MONGODB_URI environment variable inside .env.local'
  )
}

if (!MONGODB_DB) {
  throw new Error(
    'Please define the MONGODB_DB environment variable inside .env.local'
  )
}

/**
 * Global is used here to maintain a cached connection across hot reloads
 * in development. This prevents connections growing exponentially
 * during API Route usage.
 */
let cached = global.mongo

if (!cached) {
  cached = global.mongo = { conn: null, promise: null }
}

export async function connectToDatabase() {
  if (cached.conn) {
    return cached.conn
  }

  if (!cached.promise) {
    const opts = {
      useNewUrlParser: true,
      useUnifiedTopology: true,
    }

    cached.promise = MongoClient.connect(MONGODB_URI, opts).then((client) => {
      return {
        client,
        db: client.db(MONGODB_DB),
      }
    })
  }
  cached.conn = await cached.promise
  return cached.conn
}
```
Now, if we navigate to `localhost:3000/api/posts`, we'll see a result that looks like this:
![localhost2](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-21-at-5.06.41-AM.png)

Finally, let's update the `pages/index.ts` file to use this JSON response and display the formatted data on the homepage.

```JavaScript
import Head from 'next/head'
import { connectToDatabase } from '../lib/mongodb'
import { InferGetServerSidePropsType } from 'next'
import { title } from 'process';

export async function getServerSideProps(context) {
  const { db } = await connectToDatabase()
  
  const data = await db.collection("posts").find({}).toArray();

  const allposts = JSON.parse(JSON.stringify(data));
  
  return {
    props: { posts: allposts },
  }
}

export default function Home({ posts }) {

  console.log(posts);

  return (
    <div>
      <Head>
        <title>Nextbnb</title>
        <link rel="icon" href="/favicon.ico" />
        <link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet"></link>
      </Head>

      <div className="md:container md:mx-auto">
        <p>All Posts</p>
        <ul>
          {posts.map(post => (
            <li key = {post._id}>{post.title} by {post.author_name} on {post.published_on}</li>
          ))
          }
        </ul>
      </div>

    </div>
  )
}
```

Finally, navigate to `http://localhost:3000/` !

Tada 🎉 Now you can see the `posts` collection data on the homepage of the application. This is just the rough presentation of the data on the frontend - you can make further changes to improve the UI.
![collectionpost](https://blog.tooljet.com/content/images/size/w1600/2023/03/Screenshot-2023-03-21-at-5.15.52-AM.png)

### Putting it all together
In this tutorial, we walked through the MongoDB Atlas and created a database with three different collections, learned how to quickly build a multipage application using ToolJet, and finally, we connected our MongoDB database to the Next.js application and executed queries.

If you have any questions or feedback, reach out through the [ToolJet Slack community](https://tooljet.com/slack) and let me know what you want to build with ToolJet and MongoDB.