How to connect and sync Bryntum Gantt to monday.com
With Bryntum Gantt, you can build superfast 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. We’ll do the following:
- Use monday.com’s GraphQL API to get items from your monday.com boards.
- Display the monday.com items and subitems in a Bryntum Gantt chart.
- Sync event changes in Bryntum Gantt with your monday.com boards.
Getting started
Clone the starter GitHub repository. This starter repository uses 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 now 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. Follow step one of the Bryntum Gantt set up guide to log into the Bryntum registry component.
Then initialize your application using the npm CLI command:
npm init
You will be asked a series of questions in the terminal; accept all the defaults by pressing the enter key for each question.
Now follow step four of the Bryntum Gantt set up guide to install 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 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: [
{
id: 1,
name: 'Write docs',
expanded: true,
children: [
{
id: 2,
name: 'Proof-read docs',
startDate: '2023-01-02',
endDate: '2023-01-09',
manuallyScheduled: true
},
{
id: 3,
name: 'Release docs',
startDate: '2023-01-09',
endDate: '2023-01-10',
manuallyScheduled: true
}
]
}
],
},
columns: [
{ type: 'name', width: 160 }
]
});
Here we import Bryntum Gantt, 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 your Gantt chart up to display specific dates on opening. In this example, we set the startDate
to the current date and endDate
to one year from today, but you can change these dates to whatever applies to your project.
We pass in data inline to populate TaskData
for simplicity. We have a parent item with two children items within it. You can learn more about working with data in the Bryntum docs.
If you run your dev server now, you’ll see the items in our Bryntum Gantt chart:
Our Gantt chart uses the Stockholm theme, which is one of five available themes for Bryntum Gantt charts. We’ve linked 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 our customization documentation.
Now let’s learn how to retrieve a list of monday.com items from a user’s account using the monday.com GraphQL API.
Set up monday.com
You will need an account on monday.com. Sign up or log in to your monday.com account. If you’re setting up a new account, choose “items” when asked what you would like to manage and select the default configuration for the rest of the set up.
Once you’ve accessed your account, you’ll see a default table containing some items. To get monday.com to work as a Gantt chart, we’ll need to change the way the default “Date” columns work.
To do this, click the three dots on the “Date” column, click “Change column type”, and then select “Timeline”.
A new “Date” column will be generated. Delete the old column. The new “Date” column allows you to assign a timespan as a date to items, which is useful when organizing projects and due dates.
Now do the same for a subitem by clicking the arrow on the left of the top item and repeating the steps for the subitem.
Get your access token
You’ll need an access token to access the items in your monday.com table for your Bryntum Gantt chart. Click on the profile picture in the bottom left corner of the screen and then click on “Developers”.
Next, click on the “Developer” button at the top of the screen and select the “My Access Tokens” menu item.
In the developers section, you will find the access token needed to query the monday.com API. Take down this access token because we will need it later.
Use monday.com GraphQL API to access a your monday.com items
Now that we have an access token, we can use it to query the monday.com API and retrieve all the items from our boards.
In the graph.js
file, add the code below (make sure to replace <your-access-token>
with the access token you received earlier – note that for production you should rather keep your access token in an environment variable, but we’ve hard-coded it in these examples for simplicity).
import { createGantt, updateChildrenList, updateParentList } from "./main.js";
function getTasksFromMonday() {
const query = '{boards(limit:2) { name id description items { name id parent_item{id} column_values{ title id type text } } } }';
fetch("https://api.monday.com/v2", {
method: 'post',
headers: {
'Content-Type': 'application/json',
'Authorization': '<your-access-token>'
},
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 };
Here we define a function called getTasksFromMonday
that makes a query to the monday.com GraphQL API. The query is limited to two boards and returns the name, ID, description, and items from the board and the name, ID, parent item ID, and column values of each item. We will use these values to define the items that are added to our Gantt chart.
The query then initiates a few functions. The updateParentList
function adds the parent level items to a list called eventList
, then a function called updateChildrenList
adds the subitems to their appropriate parent items and returns the updated eventList
. Finally createGantt
is called which will use 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';
var isAppended = false;
getTasksFromMonday();
function createGantt(eventList) {
const columnIdList = {
parent: eventList[0].column_values[3].id
};
const parentBoardId = eventList[0].board_id;
const gantt = new Gantt({
startDate: new Date(),
endDate: new Date(new Date().getFullYear() + 1, new Date().getMonth(), new Date().getDate()),
listeners: {
dataChange: function (event) {
updateMonday(event);
}
},
project: {
tasksData: eventList,
},
column_ids: columnIdList,
board_id: parentBoardId,
columns: [
{ type: 'name', width: 160 }
]
});
if (isAppended === false) {
gantt.appendTo = document.body;
isAppended = true;
}
}
export { createGantt, updateParentList, updateChildrenList };
This is the createGantt
function that will create our Gantt instance. We use the isAppended
variable to ensure the Gantt isn’t appended twice on Vite’s page reload.
Now let’s add the updateParentList
to our code, below the createGantt
function:
function updateParentList(results, eventList) {
const parentBoard = results.data.boards[1];
for (let j = 0; j < parentBoard.items.length; j++) {
eventList.push({
id: parentBoard.items[j].id,
monday_id: parentBoard.items[j].id,
name: parentBoard.items[j].name,
startDate: parentBoard.items[j].column_values[3].text.slice(0, 10),
endDate: parentBoard.items[j].column_values[3].text.slice(13, 23),
expanded: false,
children: [],
board_id: parentBoard.id,
column_values: parentBoard.items[j].column_values,
});
}
return eventList;
}
Here the updateParentList
function loops through each of the boards that were 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 item with the updateChildrenList
function. Add these lines below the updateParentList
function:
function updateChildrenList(results, eventList) {
const childBoard = results.data.boards[0];
for (let j = 0; j < childBoard.items.length; j++) {
if (childBoard.items[j].parent_item != null) {
const parentId = childBoard.items[j].parent_item.id;
const childId = childBoard.items[j].id;
for (var k = 0; k < eventList.length; k++) {
if (parentId === eventList[k].id) {
eventList[k].children.push({
id: childId,
monday_id: childId,
name: childBoard.items[j].name,
startDate: childBoard.items[j].column_values[2].text.slice(0, 10),
endDate: childBoard.items[j].column_values[2].text.slice(13, 23),
board_id: childBoard.id,
column_values: childBoard.items[j].column_values,
manuallyScheduled: true
});
eventList[k].expanded = true;
eventList[k].endDate = childBoard.items[j].column_values[2].text.slice(13, 23);
}
}
}
}
return eventList;
}
The subitems are looped through and added to the appropriate parent item’s children
list. These events are then passed to createGantt
, which will add these items to the Gantt chart and append 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 our Gantt chart has received all the items from monday.com, we’ll implement the rest of the CRUD functionality by taking advantage of monday.com’s API.
Each of these functions requires your access token, so make sure to replace <your-access-token>
with the access token you retrieved earlier.
Create events
In the graph.js
file, add the following lines:
function addParentTaskToMonday(event, parentName, parentStart, parentEnd) {
// add a parent task to monday.com with the given parameters
let columnValues = `{\"${event.source.column_ids.parent}\" : {\"from\" : \"${parentStart}\", \"to\": \"${parentEnd}\"}}`;
columnValues = JSON.stringify(columnValues);
const query = `mutation{ create_item (board_id: ${event.source.column_ids.child}, item_name: \"${parentName}\", create_labels_if_missing: true, column_values: ${columnValues}){ id board{id} column_values{title id type text } }}`;
fetch("https://api.monday.com/v2", {
method: 'post',
headers: {
'Content-Type': 'application/json',
'Authorization': '<your-access-token>'
},
body: JSON.stringify({
'query': query
})
})
.then((result) => result.json())
.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 addParentTaskToMonday
, 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 that will be 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 created item.
Now we will define the function to create the subitems. In the graph.js
file, add the following lines:
function addTaskToMonday(event, parentId, childName, childStart, childEnd) {
// add a task to monday.com with the given parameters
let columnValues = `{\"${event.source.column_ids.child}\" : {\"from\" : \"${childStart}\", \"to\": \"${childEnd}\"}}`;
columnValues = JSON.stringify(columnValues);
const query = `mutation{ create_subitem (parent_item_id: ${parentId}, item_name: \"${childName}\", create_labels_if_missing: true, column_values: ${columnValues}){ id board{id} parent_item{id} column_values{title id type text } }}`;
fetch("https://api.monday.com/v2", {
method: 'post',
headers: {
'Content-Type': 'application/json',
'Authorization': '<your-access-token>'
},
body: JSON.stringify({
'query': query
})
})
.then((result) => result.json())
.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;
}
);
}
Similarly to our function to add a parent item, addTaskToMonday
takes in data from the appropriate Gantt chart item, uses the data to query the monday.com API, and creates a subitem-level item. The event
is used to update the Gantt item with the details from the query result of the created item.
Update events
In the graph.js
file, add the following function:
function updateTaskOnMonday(boardId, columnId, childId, childName, childStart, childEnd, updateType) {
if (updateType === "timeline") {
var columnValues = `{\"${columnId}\" : {\"from\" : \"${childStart}\", \"to\" : \"${childEnd}\"}}`
} else if (updateType === "name") {
var columnValues = `{\"name\" : \"${childName}\"}`
}
columnValues = JSON.stringify(columnValues);
const query = `mutation{ change_multiple_column_values (board_id: ${boardId}, item_id: ${childId}, column_values: ${columnValues}){ id }}`;
fetch("https://api.monday.com/v2", {
method: 'post',
headers: {
'Content-Type': 'application/json',
'Authorization': '<your-access-token>'
},
body: JSON.stringify({
'query': query
})
})
.then((result) => result.json());
}
The updateTaskOnMonday
function uses the updateType
variable to determine which 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
const query = `mutation{ delete_item (item_id: ${id}){ id }}`;
fetch("https://api.monday.com/v2", {
method: 'post',
headers: {
'Content-Type': 'application/json',
'Authorization': '<your-access-token>'
},
body: JSON.stringify({
'query': query
})
})
}
The deleteTask
function will identify the appropriate item by id
and delete 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 set the listeners for our Bryntum Gantt so that it will know when the user updates the Gantt events.
Replace the definition of gantt
with the following code:
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()),
listeners: {
dataChange: function (event) {
updateMonday(event);
}
},
project: {
tasksData: eventList,
},
column_ids: columnIdList,
columns: [
{ type: 'name', width: 160 }
]
});
Here we set a listener on our Bryntum Gantt to listen for any changes to the Gantt’s data store. This will fire an "add"
event whenever a Gantt item is created, an "update"
event when an item is updated, and a "remove"
event whenever 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’ll use the event data to identify which item is being altered and what’s being changed.
Next we’ll create a function called updateMonday
that will update monday.com when the appropriate "add"
, "update"
, or "delete"
event is fired.
Add the following code below the createGantt
function in the main.js
file:
function updateMonday(event) {
if (event.action === "add" && event.isChild === true) {
if (event.records[0]._data.parentId != null) {
const parentId = event.parent._data.monday_id;
const childName = event.records[0]._data.name;
const childStart = event.records[0]._data.startDate.toISOString().split('T')[0];
const childEnd = event.records[0]._data.endDate.toISOString().split('T')[0];
addTaskToMonday(event, parentId, childName, childStart, childEnd);
} else {
const parentName = event.records[0]._data.name;
const parentStart = event.records[0]._data.startDate.toISOString().split('T')[0];
const parentEnd = event.records[0]._data.endDate.toISOString().split('T')[0];
addParentTaskToMonday(event, parentName, parentStart, parentEnd);
}
} 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 taskId = event.record._data.monday_id;
const taskName = event.record._data.name;
const taskStart = event.record._data.startDate.toISOString().split('T')[0];
const taskEnd = event.record._data.endDate.toISOString().split('T')[0];
const boardId = event.record._data.board_id;
const columnId = event.record._data.column_values[event.record._data.column_values.length - 1].id;
updateTaskOnMonday(boardId, columnId, taskId, taskName, taskStart, taskEnd, updateType);
}
}
} else if (event.action === "remove") {
if (event.isCollapse !== true) {
const taskId = event.records[0]._data.monday_id;
deleteTask(taskId);
}
}
}
Here we create a function that is called on all changes to the data store of Bryntum Gantt, which then calls one of the monday.com API CRUD functions we defined.
On "add"
, we check whether the item being created is a parent item or a subitem. If the item is a subitem, then addTaskToMonday
is called with data from the event
and the item is created on monday.com.
function updateMonday(event) {
if (event.action === "add" && event.isChild === true) {
if (event.records[0]._data.parentId != null) {
const parentId = event.parent._data.monday_id;
const childName = event.records[0]._data.name;
const childStart = event.records[0]._data.startDate.toISOString().split('T')[0];
const childEnd = event.records[0]._data.endDate.toISOString().split('T')[0];
addTaskToMonday(event, parentId, childName, childStart, childEnd);
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 parentName = event.records[0]._data.name;
const parentStart = event.records[0]._data.startDate.toISOString().split('T')[0];
const parentEnd = event.records[0]._data.endDate.toISOString().split('T')[0];
addParentTaskToMonday(event, parentName, parentStart, parentEnd);
}
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 the updateType
so that the appropriate query can be called in the updateTaskOnMonday
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 taskId = event.record._data.monday_id;
const taskName = event.record._data.name;
const taskStart = event.record._data.startDate.toISOString().split('T')[0];
const taskEnd = event.record._data.endDate.toISOString().split('T')[0];
const boardId = event.record._data.board_id;
const columnId = event.record._data.column_values[event.record._data.column_values.length - 1].id;
updateTaskOnMonday(boardId, columnId, taskId, taskName, taskStart, taskEnd, updateType);
}
}
}
Finally, 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 taskId = event.records[0]._data.monday_id;
deleteTask(taskId);
}
}
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 the Bryntum Gantt chart. You’ll see the changes reflected in monday.com.
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 features such as tree grouping. Take a look at our demos page to see demos of the available features.