DHTMLX Kanban. Real-time multiuser backend example
When multiple users work on the same board simultaneously, changes made by one user need to appear on everyone else's screen in real time. The multiuser backend setup adds a WebSocket connection on top of the standard REST integration to push updates to all connected clients.
Live example
// Check Go backend repository here - https://github.com/web-widgets/kanban-go
const url = "https://docs.dhtmlx.com/kanban-backend";
const {
Kanban,
Toolbar,
RestDataProvider,
RemoteEvents,
kanbanUpdates,
defaultEditorShape,
defaultCardShape,
} = kanban;
const cardShape = {
...defaultCardShape,
label: true,
description: true,
progress: true,
start_date: true,
end_date: true,
priority: true,
color: true,
cover: true,
attached: true,
users: {
show: true,
values: users,
},
};
const editorShape = [
...defaultEditorShape,
{
key: "attached",
type: "files",
label: "Files",
uploadURL: url + "/uploads",
},
];
const restProvider = new RestDataProvider(url);
function login(url) {
// uncomment if you use this in code outside of this demo
/*var token = sessionStorage.getItem("login-token");
if (token) {
return Promise.resolve(token);
}*/
return fetch(url + "/login?id=1")
.then(raw => raw.text())
.then(token => {
sessionStorage.setItem("login-token", token);
return token;
});
}
login(url).then(token => {
const restProvider = new RestDataProvider(url);
restProvider.setHeaders({
"Remote-Token": token,
});
Promise.all([
restProvider.getCards(),
restProvider.getColumns(),
restProvider.getRows(),
]).then(([cards, columns, rows]) => {
const board = new Kanban("#root", {
cards,
columns,
rows,
rowKey: "row",
cardShape,
editorShape,
});
new Toolbar("#toolbar", { api: board.api });
board.api.setNext(restProvider);
const events = new RemoteEvents(url + "/api/v1", token);
const handlers = kanbanUpdates(
board.api,
restProvider.getIDResolver()
);
events.on(handlers);
});
});
<!-- component containers -->
<div id="toolbar"></div>
<div id="root" style="height: calc(100% - 56px);"></div>
<!-- dataset -->
<script>
const users = [
{
id: 1,
label: "Steve Smith",
avatar: "https://snippet.dhtmlx.com/codebase/data/kanban/01/img/user-1.jpg",
},
{
id: 2,
label: "Aaron Long",
avatar: "https://snippet.dhtmlx.com/codebase/data/kanban/01/img/user-2.jpg",
},
{
id: 3,
label: "Angela Allen",
avatar: "https://snippet.dhtmlx.com/codebase/data/kanban/01/img/user-3.jpg",
},
{
id: 4,
label: "Angela Long",
avatar: "https://snippet.dhtmlx.com/codebase/data/kanban/01/img/user-4.jpg",
},
{
id: 5,
label: "John Doe",
},
];
</script>The code adds two key components beyond the basic backend setup: RemoteEvents opens a WebSocket connection to the server, and kanbanUpdates creates event handlers that apply remote changes to the local board. The RemoteEvents instance listens at url + "/api/v1" with the user's auth token, and kanbanUpdates receives the board API and an ID resolver (to map temporary IDs to server-assigned IDs). The events.on(handlers) call wires everything together.
Solution overview
- Set up basic backend integration with
RestDataProviderand authentication - Create a WebSocket connection:
const events = new RemoteEvents(url + "/api/v1", token) - Create update handlers:
const handlers = kanbanUpdates(board.api, restProvider.getIDResolver()) - Connect them:
events.on(handlers)
Key points
RemoteEventsuses WebSockets: Thehttp(s)://URL is converted tows(s)://automatically, opening a persistent WebSocket connection for bidirectional real-time updateskanbanUpdateshandles ID resolution: When one user creates a card, they get a temporary ID until the server responds.getIDResolver()maps these temp IDs to real ones so remote updates reference the correct cards- Changes reflect instantly: When another user adds, moves, or edits a card, the local board updates automatically through the WebSocket handlers
- Auth token required: The
RemoteEventsconnection needs the same auth token used for REST. It identifies which user's changes to exclude from the WebSocket stream
API reference
- RemoteEvents: WebSocket client for real-time updates
- kanbanUpdates: Creates handlers for applying remote changes
- RestDataProvider: REST client with
getIDResolverfor temp-to-real ID mapping
Related examples
- Backend
- Undo/redo with backend
- Backend with comments and votes
- Kanban + Gantt + Calendar + Todo (real-time backend)