How to connect and sync Bryntum Gantt to monday.com
With Bryntum Gantt, you can build super fast and fully customizable Gantt charts with pure JavaScript. You can easily use Bryntum Gantt with React, Vue, or Angular.
In this tutorial, we’ll connect and sync Bryntum Gantt to monday.com by:
- Using the monday.com GraphQL API to get items from your monday.com boards.
- Displaying the monday.com items and subitems in a Bryntum Gantt chart.
- Syncing event changes in Bryntum Gantt with your monday.com boards.
Getting started
Clone the starter GitHub repository. This starter repository uses the development server and JavaScript bundler, Vite. You’ll need Node.js version 14.18+ for Vite to work.
Install the Vite dev dependency by running the following command:
npm install
The dev server is configured to run on http://localhost:8080/
in the vite.config.js
file.
Run the local dev server using npm run dev
and you’ll see a blank page.
Create a Gantt chart using Bryntum Gantt
We’ll install the Bryntum Gantt component using npm.
Use the guide to using the Bryntum npm repository to log in to the Bryntum component registry.
Then, install Bryntum Gantt by following step four of the guide to getting started with Bryntum Gantt.
Let’s import the Bryntum Gantt component and give it some basic configuration. In the main.js
file, add the following lines:
import { Gantt } from '@bryntum/gantt/gantt.module.js';
const gantt = new Gantt({
appendTo: document.body,
startDate: '2025-01-01',
endDate: new Date(new Date().getFullYear() + 1, new Date().getMonth(), new Date().getDate()),
project: {
tasksData: [
{
id: 1,
name: 'Write docs',
expanded: true,
children: [
{
id: 2,
name: 'Proof-read docs',
startDate: '2025-01-02',
endDate: '2025-01-09',
manuallyScheduled: true
},
{
id: 3,
name: 'Release docs',
startDate: '2025-01-09',
endDate: '2025-01-10',
manuallyScheduled: true
}
]
}
],
},
columns: [
{ type: 'name', width: 200 }
]
});
Here, we import the component, create a new Bryntum Gantt instance, and pass a configuration object into it. We add the Gantt chart to the <body>
of the DOM.
You can set up your Gantt chart so that it displays specific dates on opening. In this example, we set the startDate
to the current date and the endDate
to one year from today, but you can change these dates to the duration of your project.
For simplicity, we populate TaskData
by passing in data inline. We have a parent item containing two children items. You can learn more about working with data in the Bryntum docs.
If you run your dev server now, you’ll see the parent and children items in the Bryntum Gantt chart:
The Gantt chart uses the Stockholm theme, which is one of five available themes for Bryntum Gantt charts. There is a link to the CSS for the Stockholm theme in index.html
. If you’d like to create a custom theme, read more about styling your Gantt chart in the Bryntum customization docs.
Now, let’s learn how to use the monday.com GraphQL API to retrieve a list of items from a monday.com user account.
Set up monday.com
Sign up or log in to monday.com. If you’re setting up a new personal account, click the Continue button when asked what you want to manage first:
Click Continue again when asked what you want to focus on first:
Name your board Bryntum Monday Integration
:
Select the Owner, Status, and Timeline columns for your board. These can also be added later.
Select the Tasks overview, Tasks by status, and Tasks by owner widgets for your dashboard:
Add the Gantt view layout:
Click the Get started button in the List your projects step:
You’ll see your Bryntum Monday Integration board and three example tasks displayed on the monday.com work management dashboard:
Delete the Due date column by hovering over the header name, clicking the ellipsis icon, and selecting the Delete menu item. Delete the Dependent On column too, as we won’t work with task dependencies in this guide.
Rename the Timeline column Dates
.
Add a Subitem called Task 3 subtask 1
to Task 3. Then, rename the Date column Dates
and change it to a timeline column by hovering over the column name, Dates, clicking the ellipsis icon, selecting Change column type from the menu, and choosing Timeline. This creates a new column. Delete the old Dates column and set the dates for the subtask in the new column.
Get your access token
You need an access token to access the monday.com board items for your Bryntum Gantt component. Click on your profile picture in the top-right corner of the screen and select Developers in the popup menu:
This opens the monday.com Developer Center. Open the My access tokens page from the left-hand navigation panel. Click Show to reveal and copy your access token.
Save the access token to use later.
Using the monday.com GraphQL API playground
The monday.com API is built with GraphQL and has a GraphQL playground for testing and building your queries. To access it, open the API playground page from the Developer Center navigation panel.
You can edit the GraphQL query and then execute it by clicking the “Execute query” button represented by the blue play icon.
Use the monday.com GraphQL API to access your monday.com items
Now that you have an access token, we can use it to query the monday.com API and retrieve all the items from our boards.
Create a .env
file in the root folder of your project and add your access token to the following environment variable:
VITE_MONDAY_ACCESS_TOKEN=
For simplicity, we’ll use the Fetch API on the client side with this access token.
Alternatively, you can learn how to protect your access token in an Express.js server in the guide to connecting Bryntum Scheduler Pro to monday.com, which uses the monday.com SDK rather than the Fetch API to import data to a Bryntum component.
In the graph.js
file, add the code below:
import { createGantt, updateChildrenList, updateParentList, accessToken } from "./main.js";
function getTasksFromMonday() {
const query = `{
boards(limit: 2) {
id
items_page {
items {
id
name
parent_item{id}
column_values {
id
text
value
column {
title
settings_str
}
}
}
}
}
}`;
fetch("https://api.monday.com/v2", {
method: 'post',
headers: {
'Content-Type': 'application/json',
'Authorization' : accessToken,
'API-Version' : '2024-10'
},
body: JSON.stringify({
'query': query
})
})
.then((result) => result.json())
.then(res => {
let eventList = [];
eventList = updateParentList(res, eventList);
eventList = updateChildrenList(res, eventList);
createGantt(eventList);
});
}
export { getTasksFromMonday };
In this code, we define a getTasksFromMonday
function, which makes a query to the monday.com GraphQL API. The query is limited to two boards and returns the items from each board. We query the name, ID, parent item ID, and column values of each item. We’ll use these values to define the items added to the Bryntum Gantt.
The query then initiates a few functions: The updateParentList
function adds the parent-level items to a list called eventList
, the updateChildrenList
function adds the subitems to their appropriate parent items and returns the updated eventList
, and the createGantt
function uses the data from the eventList
to create the Gantt instance and TaskData
.
Replace all the code in the main.js
file with the following code:
import { Gantt } from '@bryntum/gantt/gantt.module.js';
import { getTasksFromMonday } from './graph.js';
const accessToken = import.meta.env.VITE_MONDAY_ACCESS_TOKEN
let isAppended = false;
getTasksFromMonday();
function createGantt(eventList) {
let column_id_list_child;
for (let i = 0; i < eventList.length; i++) {
if (eventList[i]?.children.length > 0) {
column_id_list_child = eventList[i].children[0].column_values[2].id;
break;
}
}
const column_id_list = {child: column_id_list_child, parent: eventList[0].column_values[3].id};
const parent_board_id = eventList[0].board_id;
const gantt = new Gantt({
// startDate is today and endDate is 1 year from today
startDate: new Date(),
endDate: new Date(new Date().getFullYear() + 1, new Date().getMonth(), new Date().getDate()),
project : {
tasksData : eventList,
},
column_ids: column_id_list,
board_id: parent_board_id,
columns : [
{ type : 'name', width : 200 }
]
});
if(isAppended == false){
gantt.appendTo = document.body;
isAppended = true;
}
}
export { createGantt, updateParentList, updateChildrenList, accessToken };
The above createGantt
function creates our Gantt instance. In it, we use the isAppended
variable to ensure the Gantt isn’t appended twice when the Vite page reloads and use the column_id_list_child
variable to save the ID of the column containing subitems. This only works if there is a subitem in your Gantt. If not, you need to manually add this value.
If you run the GraphQL query used in the getTasksFromMonday
function in the monday.com GraphQL playground, you can see the column_value
IDs. The ID for the Dates column containing subitems has a random string in it: "id": "dates_mkm2h7bj",
.
Now let’s add the updateParentList
to our code. Insert the following below the createGantt
function:
function updateParentList(results, eventList) {
let parent_board = results.data.boards[1];
for (let j = 0; j < parent_board.items_page.items.length; j++) {
eventList.push({
id: parent_board.items_page.items[j].id,
monday_id : parent_board.items_page.items[j].id,
name : parent_board.items_page.items[j].name,
startDate : parent_board.items_page.items[j].column_values[3].text.slice(0,10),
endDate : parent_board.items_page.items[j].column_values[3].text.slice(13,23),
expanded : false,
children : [],
board_id: parent_board.id,
column_values: parent_board.items_page.items[j].column_values,
manuallyScheduled: true
});
}
return eventList;
}
Here, the updateParentList
function loops through each of the boards returned from the getTasksFromMonday
query. Each item from the parent_board
is added to the eventList
.
Now let’s add all subitems to their parent items with the updateChildrenList
function. Add these lines below the updateParentList
function:
function updateChildrenList(results, eventList) {
let child_board = results.data.boards[0];
for (let j = 0; j < child_board.items_page.items.length; j++) {
if(child_board.items_page.items[j].parent_item != null){
const parent_id = child_board.items_page.items[j].parent_item.id;
const child_id = child_board.items_page.items[j].id;
for (let k = 0; k < eventList.length; k++) {
if (parent_id == eventList[k].id ) {
eventList[k].children.push({
id : child_id,
monday_id : child_id,
name : child_board.items_page.items[j].name,
startDate : child_board.items_page.items[j].column_values[2].text.slice(0,10),
endDate : child_board.items_page.items[j].column_values[2].text.slice(13,23),
board_id: child_board.id,
column_values: child_board.items_page.items[j].column_values,
manuallyScheduled: true
});
eventList[k].expanded = true;
eventList[k].endDate = child_board.items_page.items[j].column_values[2].text.slice(13,23);
}
}
}
}
return eventList;
}
This function loops through the subitems and adds them to the appropriate parent item’s children
list. These events are then passed to the createGantt
function, which adds these items to the Gantt chart and appends the chart to the body of the DOM.
If you run the server now, you will see the items from your monday.com boards reflected in the Bryntum Gantt chart.
Implementing CRUD
Now that the Gantt chart has received all the items from monday.com, we’ll implement the rest of the CRUD functionality by taking advantage of the monday.com API. Each of the CRUD functions requires your access token.
Create events
In the graph.js
file, add the following lines:
function addParentTaskToMonday(event, parent_name, parent_start, parent_end) {
// add a parent task to monday.com with the given parameters
let column_values = `{\"${event.source.column_ids.parent}\" : {\"from\" : \"${parent_start}\", \"to\": \"${parent_end}\"}}`;
column_values = JSON.stringify(column_values);
let query = `mutation{ create_item (board_id: ${event.source.board_id}, item_name: \"${parent_name}\", create_labels_if_missing: true, column_values: ${column_values}){ id board{id} column_values{id type text } }}`;
const response = fetch ("https://api.monday.com/v2", {
method: 'post',
headers: {
'Content-Type': 'application/json',
'Authorization' : accessToken,
'API-Version' : '2024-10'
},
body: JSON.stringify({
'query' : query
})
})
.then(result => {
let res = result.json();
return res;
})
.then(res => {
event.records[0].data.monday_id = res.data.create_item.id;
event.records[0].data.board_id = res.data.create_item.board.id;
event.records[0].data.column_values = res.data.create_item.column_values;
event.records[0].data.manuallyScheduled = true;
})
}
Here, we define the addParentTaskToMonday
function, which takes in data from a parent item, uses this data to query the monday.com API, and creates a parent-level item. The event
represents an object passed from a listener, which we will set up later. The event
is used here to update the Gantt item with the details from the query result of the newly created parent-level item.
Now, we will define the function that creates the subitems. In the graph.js
file, add the following lines of code:
function addTaskToMonday(event, parent_id, child_name, child_start, child_end) {
// add a task to monday.com with the given parameters
let column_values = `{\"${event.source.column_ids.child}\" : {\"from\" : \"${child_start}\", \"to\": \"${child_end}\"}}`;
column_values = JSON.stringify(column_values);
let query = `mutation{ create_subitem (parent_item_id: ${parent_id}, item_name: \"${child_name}\", create_labels_if_missing: true, column_values: ${column_values}){ id board{id} parent_item{id} column_values{ id type text } }}`;
const response = fetch ("https://api.monday.com/v2", {
method: 'post',
headers: {
'Content-Type': 'application/json',
'Authorization' : accessToken,
'API-Version' : '2024-10'
},
body: JSON.stringify({
'query' : query
})
})
.then(result => {
let res = result.json();
return res;
})
.then(res => {
event.records[0].data.monday_id = res.data.create_subitem.id;
event.records[0].data.board_id = res.data.create_subitem.board.id;
event.records[0].data.parentId = res.data.create_subitem.parent_item.id;
event.records[0].data.column_values = res.data.create_subitem.column_values;
event.records[0].data.manuallyScheduled = true;
}
);
}
Similar to the addParentTaskToMonday
function, the addTaskToMonday
function takes in data from the appropriate Gantt chart item, uses the data to query the monday.com API, and creates a subitem. The event
is used to update the Gantt item with the details from the query result of the newly created item.
Update events
In the graph.js
file, add the following function:
function updateTaskOnMonday(board_id, column_id, child_id, child_name, child_start, child_end, updateType) {
if(updateType == "timeline") {
var column_values = `{\"${column_id}\" : {\"from\" : \"${child_start}\", \"to\" : \"${child_end}\"}}`
} else if (updateType == "name") {
var column_values = `{\"name\" : \"${child_name}\"}`
}
column_values = JSON.stringify(column_values);
let query = `mutation{ change_multiple_column_values (board_id: ${board_id}, item_id: ${child_id}, column_values: ${column_values}){ id }}`;
const response = fetch ("https://api.monday.com/v2", {
method: 'post',
headers: {
'Content-Type': 'application/json',
'Authorization' : accessToken,
'API-Version' : '2024-10'
},
body: JSON.stringify({
'query' : query
})
})
.then(result => {
let res = result.json();
return res;
})
}
The updateTaskOnMonday
function uses the updateType
variable to determine which monday.com columns to query for the update. Either the Date column or the Name column will be updated and the appropriate query will be constructed.
Delete events
In the graph.js
file, add the following function:
function deleteTask(id) {
// delete a task on monday.com with the given parameters
let query = `mutation{ delete_item (item_id: ${id}){ id }}`;
const response = fetch ("https://api.monday.com/v2", {
method: 'post',
headers: {
'Content-Type': 'application/json',
'Authorization' : accessToken,
'API-Version' : '2024-10'
},
body: JSON.stringify({
'query' : query
})
})
}
The deleteTask
function identifies the appropriate item by id
and deletes the item.
Now, replace the exports at the bottom of graph.js
with the following line:
export { getTasksFromMonday, addTaskToMonday, addParentTaskToMonday, updateTaskOnMonday, deleteTask };
Listening for event data changes in Bryntum Gantt
Next, we’ll add a data change event listener to the Bryntum Gantt, so that we can update the monday.com board when data in the Bryntum Gantt changes.
Add the following listeners
config to the gantt
instance in the main.js
file:
listeners: {
dataChange: function (event) {
updateMonday(event);
}
},
Here, we set a listener on our Bryntum Gantt to listen for any changes to the Gantt’s data store and to fire an "add"
event when a Gantt item is created, an "update"
event when an item is updated, and a "remove"
event when an item is deleted.
The item retrieved from the dataChange
listener also carries event data about the specific Gantt item that has been altered. We use the event data to identify the altered item and how it has been changed.
Next, we’ll create an updateMonday
function that updates monday.com when the appropriate "add"
, "update"
, or "delete"
event is fired.
Add the following code to the main.js
file, below the createGantt
function:
function updateMonday(event) {
if(event.action == "add" && event.isChild == true){
// if the task is a child task
if(event.records[0].data.parentId != null && !event.records[0].data.parentId.startsWith("_generatedProjectModel")){
const parent_id = event.parent.data.monday_id;
const child_name = event.records[0].data.name;
const child_start = event.records[0].data.startDate.toISOString().split('T')[0];
const child_end = event.records[0].data.endDate.toISOString().split('T')[0];
addTaskToMonday(event, parent_id, child_name, child_start, child_end);
// if the task is a parent task
} else {
const parent_id = event.records[0].data.id;
const parent_name = event.records[0].data.name;
const parent_start = event.records[0].data.startDate.toISOString().split('T')[0];
const parent_end = event.records[0].data.endDate.toISOString().split('T')[0];
addParentTaskToMonday(event, parent_name, parent_start, parent_end);
}
} else if (event.action == "update"){
if("startDate" in event.changes || "endDate" in event.changes || "name" in event.changes){
if ("column_values" in event.records[0].data){
if ("name" in event.changes){
var updateType = "name";
} else if ("startDate" in event.changes || "endDate" in event.changes){
var updateType = "timeline";
}
const task_id = event.record.data.monday_id;
const task_name = event.record.data.name;
const task_start = event.record.data.startDate.toISOString().split('T')[0];
const task_end = event.record.data.endDate.toISOString().split('T')[0];
const board_id = event.record.data.board_id;
const column_id = event.record.data.column_values[event.record.data.column_values.length - 1].id;
updateTaskOnMonday(board_id, column_id, task_id, task_name, task_start, task_end, updateType);
}
}
} else if (event.action == "remove"){
if(event.isCollapse != true){
const task_id = event.records[0].data.monday_id;
deleteTask(task_id);
}
}
}
The above updateMonday
function is called on all changes to the data store of Bryntum Gantt. We use it to call one of the monday.com API CRUD functions we defined, as follows:
- On
"add"
, we check whether the item being created is a parent item or a subitem. If the item is a subitem, thenaddTaskToMonday
is called with data from theevent
, and the item is created on monday.com.
function updateMonday(event) {
if(event.action == "add" && event.isChild == true){
// if the task is a child task
if(event.records[0].data.parentId != null && !event.records[0].data.parentId.startsWith("_generatedProjectModel")){
const parent_id = event.parent.data.monday_id;
const child_name = event.records[0].data.name;
const child_start = event.records[0].data.startDate.toISOString().split('T')[0];
const child_end = event.records[0].data.endDate.toISOString().split('T')[0];
addTaskToMonday(event, parent_id, child_name, child_start, child_end);
If the item is a parent item, then addParentTaskToMonday
is called with data from the event
and the item is created on monday.com.
} else {
const parent_id = event.records[0].data.id;
const parent_name = event.records[0].data.name;
const parent_start = event.records[0].data.startDate.toISOString().split('T')[0];
const parent_end = event.records[0].data.endDate.toISOString().split('T')[0];
addParentTaskToMonday(event, parent_name, parent_start, parent_end);
}
- On
"update"
, we check whether the update is relevant to our monday.com items. If the update includes"startDate"
,"endDate"
, or"name"
data and data for"column_values"
, then the task is a monday.com item. Then we establish theupdateType
so that the appropriate query can be called in theupdateTaskOnMonday
function.
} else if (event.action == "update"){
if("startDate" in event.changes || "endDate" in event.changes || "name" in event.changes){
if ("column_values" in event.records[0].data){
if ("name" in event.changes){
var updateType = "name";
} else if ("startDate" in event.changes || "endDate" in event.changes){
var updateType = "timeline";
}
const task_id = event.record.data.monday_id;
const task_name = event.record.data.name;
const task_start = event.record.data.startDate.toISOString().split('T')[0];
const task_end = event.record.data.endDate.toISOString().split('T')[0];
const board_id = event.record.data.board_id;
const column_id = event.record.data.column_values[event.record.data.column_values.length - 1].id;
updateTaskOnMonday(board_id, column_id, task_id, task_name, task_start, task_end, updateType);
}
}
If the dataChange
event is a "remove"
event, then we delete the matching monday.com item using the deleteTask
function.
} else if (event.action == "remove"){
if (event.isCollapse != true) {
const task_id = event.records[0].data.monday_id;
deleteTask(task_id);
}
}
Finally, change the imports at the top of the main.js
file to the following:
import { Gantt } from '@bryntum/gantt/gantt.module.js';
import { getTasksFromMonday, addTaskToMonday, updateTaskOnMonday, addParentTaskToMonday, deleteTask } from './graph.js';
Now try to create, update, delete, and edit an item in your Bryntum Gantt component. You’ll see the changes reflected in monday.com.
You can use the monday.com Gantt view layout to represent your data as a Gantt chart.
Next steps
This tutorial gives you a starting point for creating a Bryntum Gantt chart using vanilla JavaScript and syncing it with monday.com.
There are many ways you can improve your Bryntum Gantt chart. For example, you can add indenting and outdenting functionalities to the Bryntum Gantt, which change a task’s position in the task tree when changes are made to the task’s parent ID value.
You can also save changes to task dependencies, as monday.com supports task dependencies. However, you can’t save changes to the order of your tasks in the Bryntum Gantt, as the feature allowing you to use the monday.com API to change the order of board items is still being developed.
Take a look at our demos page to see the features available for you to add to your Bryntum Gantt.