Real-Time Angular Gantt Chart with SignalR: Multi-User Project Sync Without Refresh

Summarize this blog post with:

TLDR: Concurrency issues don’t break your Gantt chart UI; they break trust in the data. The moment multiple users start editing, timelines drift, updates get missed, and teams fall back to manual coordination. This approach changes that. By integrating SignalR into your Angular Gantt Chart, wiring a lightweight backend hub, real-time client listeners, and event-driven updates, you turn a static timeline into a live, shared system. No polling, no refreshes, no guesswork; just instant updates and a consistent view for every user, exactly when it matters.

In most project management tools, things start breaking the moment multiple users start editing at the same time.

  • One person updates a task.
  • Another modifies dependency.
  • Someone else shifts a timeline.

Before long, everyone looks at a slightly different version of the same data.

A Gantt Chart helps organize all of this; it visualizes dependencies, timelines, and resources clearly. But by default, it’s still just a local snapshot. Once multiple users are involved, keeping everyone in sync becomes the real problem.

This is where real-time updates change the behavior completely.

Instead of relying on refreshes or polling, SignalR keeps a persistent connection and pushes updates instantly to all connected clients.

The result is simple: everyone sees the same timeline, in real time, without second-guessing whether their view is up to date.

In this guide, we’ll walk you through integrating SignalR into the Syncfusion® Angular Gantt Chart setup to make that happen.

What you gain: a timeline that stays in sync automatically

Once real-time updates are in place, the Gantt Chart behaves more like a shared system than a static UI:

  • Immediate updates: Changes made by one user appear for everyone instantly.
  • No refresh cycles: The UI stays current without manual intervention.
  • Event-driven behavior: Updates are pushed only when something changes.
  • Less coordination overhead: Everyone stays aligned without follow-ups.

Where this approach actually matters

Integrating SignalR with the Angular Gantt Chart is most useful when multiple roles interact with the same timeline.

For example, in a sprint planning tool:

  • A product owner adjusts deadlines.
  • Developers update tasks and dependencies.
  • QA engineer modifies testing windows.

Without real-time sync, updates get missed or overwritten, and teams fall back to messaging each other for confirmation.

With SignalR in place, the Gantt Chart behaves like a shared workspace; updates are visible immediately, and everyone works off the same state.

You’ll see similar benefits in tools like:

  • Construction scheduling,
  • Resource planning dashboards, or
  • Internal workflow trackers,

….. and anywhere multiple users actively edit the timeline.

What you need to get started

The setup is fairly lightweight:

  • Visual Studio or VS Code
  • Angular application
  • .NET 8+ backend
  • SignalR
  • Node.js and Angular CLI (ng new gantt-signalr)
  • A valid Syncfusion license key

Setting up the backend: .NET Core with SignalR

Before jumping onto the Angular side, it’s worth getting the backend ready. This is where the real-time behavior actually lives. Instead of thinking of it as just another API, think of it more like an event relay that pushes updates whenever something changes.

If you’ve tried solving multi-user sync with polling before, you already know how quickly it becomes inefficient. SignalR avoids that entirely by maintaining a connection and pushing updates only when needed.

#1: Getting a basic API in place

Start with a standard ASP.NET Core Web API project. Nothing unusual here.

If you already have a backend serving your Gantt data, you’re in a good place; you don’t need to rebuild anything. Just add SignalR on top of what you already have.

#2: Adding the SignalR hub (your real-time bridge)

Once the project is ready, the next step is adding a hub.

Create a folder called Hubs, and inside that add a file named ChatHub.cs. This hub defines the SendMessage method that broadcasts messages to all connected clients.

using Microsoft.AspNetCore.SignalR;

namespace GanttSignalRBackend.Hubs
{
    public class ChatHub : Hub
    {
        public async Task SendMessage(string message)
        {
            await Clients.All.SendAsync("ReceiveMessage", message);
        }
    }
}

At this point, you’re not doing anything complex; you’re just broadcasting a message to every connected client. That’s enough to build your sync loop.

#3: Wiring it up so Angular can talk to it

With the hub in place, the next step is to register SignalR services and enable CORS (Cross-Origin Resource Sharing) and make sure your frontend can actually connect to it.

using signalR.Hubs;

builder.Services.AddSignalR(); // Add SignalR services

builder.Services.AddCors(options =>
{
    options.AddDefaultPolicy(policy =>
    {
        policy.WithOrigins("https://localhost:7297") // Angular dev server
              .AllowAnyHeader()
              .AllowAnyMethod()
              .AllowCredentials();
    });
});

The CORS setup is important during development, since our Angular app typically runs on a different port. Without it, the connection won’t go through.

#4: Run the project

At this point, you can just start the backend using the following command:

dotnet run

It should start on:

https://localhost:7297(or a similar port).

Now, the backend is ready! It can accept connections and push updates to any client that’s listening.

Setting up the frontend: Angular with Syncfusion Gantt Chart

With the backend ready to push updates, the front-end is where things start to feel different.

Up until now, your Gantt chart has probably behaved like a snapshot; render data once, and that’s it. Now, you’re going to make it react to changes happening elsewhere.

You don’t need a complex setup to get there. A regular Angular app with a working Gantt chart is enough.

#1: Start with your usual Angular setup

Create your Angular project and set up the Gantt Chart however you normally would. Nothing has changed here yet.

#2: Add the SignalR client package

To handle real-time updates, we need the SignalR client:

npm install @microsoft/signalr –save

Once that’s installed, Angular is ready to connect to the backend and start listening for updates.

#3: Register the Syncfusion license key

Before moving further, make sure your license key is registered in your component:

import { registerLicense } from '@syncfusion/ej2-base';
registerLicense('YOUR_SYNC FUSION_LICENSE_KEY');

After that, your Gantt Chart setup remains exactly as usual.

#4: Connecting user actions to real-time updates

Now comes the part that actually changes behavior.

Instead of just updating the UI locally, you’ll start broadcasting those changes so every connected user sees them.

At a minimum, you only need two hooks from the Gantt Chart:

  • created → when the chart initializes.
  • actionComplete → when a user makes a change.
<ejs-gantt id="ganttDefault"  (actionComplete)="actionComplete($event)" (created)="created()" >
    ...
</ejs-gantt>

These two events are enough to build the entire real-time loop.

#5: Implement SignalR connection

The next step is getting your Angular app to actually connect to it.

This happens inside the ngOnInit() method, where you create a SignalR connection. Think of this as preparing a live channel for your server but not opening it just yet.

We’ll use the HubConnectionBuilder from the @microsoft/signalr library to configure that connection:

import { HubConnection} from '@microsoft/signalr';
import * as signalR from '@microsoft/signalr';

private connection!: HubConnection;
...
public ngOnInit(): void {
    ...
    this.connection = new signalR.HubConnectionBuilder()
        .withUrl("https://localhost:7297/chatHub", {
        withCredentials: true
    })
    .configureLogging(signalR.LogLevel.Information)
    .build();
}

A couple of things are happening here (nothing complicated, but worth understanding):

  • The withUrl() method specifies the hub endpoints and allows credentials, which is useful if your app relies on authentication.
  • The configureLogging() method just helps during development; you’ll see useful logs if something goes wrong.
  • The build() method creates the connection object.

At this stage, the connection is only configured, not active yet. No network calls are happening, and nothing is listening.

That’s intentional, you’ll actually start the connection and attach listeners in the next step, once your Gantt component is ready.

#6: Establishing the connection when the Gantt loads

At this point, you’ve defined the SignalR connection, but it’s still not doing anything yet.

The right moment to bring it to life is when your Gantt chart is initializing. That’s exactly what the created() hook is for. It runs just before the chart is rendered, which makes it a good place to both start the connection and hook into incoming updates.

First, you register a listener:

created()
{
    this.connection.on("ReceiveMessage", (message: string) => {
        const gantt = (document.getElementsByClassName('e-gantt')[0] as HTMLFormElement)["ej2_instances"][0];
        gantt.refresh();
    });

This does one simple but important thing:

  • Whenever the server broadcasts a “ReceiveMessage” event, you refresh the Gantt chart.

You’re not manually merging changes or reconciling state here; the refresh ensures the UI always reflects the latest data. Simple and reliable.

Once the listener is in place, you can safely start the connection:

this.connection.start()
      .then(() =>
      {
          console.log("SignalR connection established successfully");
          return this.connection.invoke('SendMessage', "refreshPages");
      })
      .catch((err: Error) => {
        console.error("Error establishing SignalR connection:", err.toString());
    });
}

A couple of things to notice here:

  • The connection only starts after the listener is ready—so you don’t miss any updates.
  • On a successful connection, you immediately invoke SendMessage. This acts like a quick “sync signal,” making sure other clients are aware of this new connection.
  • If something goes wrong, you’ll see it in the logs instead of silently failing.

Broadcasting changes when users interact

So far, your app can receive updates. Now it needs to send them.

Whenever a user edits the Gantt chart—adding a task, updating one, or deleting—you want that change to propagate to everyone else.

That’s where the actionComplete() method comes in.

actionComplete(args: any)
{
    if (args.requestType === 'save' || args.requestType === "add" || args.requestType === 'delete')
    {
        //send a message from a connected client to all clients.
        this.connection.invoke('SendMessage', "refreshPages")
          .catch((err: Error ) => {
            console.error(err.toString());
        });
    }
}

Here’s what’s happening:

  • You watch for meaningful changes (add, edit, delete).
  • When one occurs, you send a message to the hub.
  • The hub broadcasts that message to all connected clients.
  • Every client (including this one) receives it and refreshes.

That’s the full loop: user action → broadcast → all clients updates.

No polling, no manual refresh, and no guessing whether your data is stale.

#7: Test real-time synchronization

Once everything is wired up, run your Angular app:

ng serve or npm start

With the backend and frontend configured, it’s time to verify that real-time collaboration works as expected.

  • Open your app in two browser tabs.
  • Make a change in one tab.
  • Watch the other update instantly.

That moment when both screens stay in sync is where the whole setup clicks.

Integrating Angular Gantt Chart with SignalR for real-time multi-user project synchronization
Integrating Angular Gantt Chart with SignalR for real-time multi-user project synchronization

GitHub reference

For more details, refer to the example for connecting real-time data to Angular Gantt Chart using SignalR on GitHub.

Frequently Asked Questions

Why is my Angular Gantt chart not updating even though SignalR messages are received?

This usually happens when incoming SignalR data is not properly mapped to the Gantt chart’s data source, or when Angular change detection is not triggered. You must explicitly update the Gantt dataSource (or use methods like refresh()/setProperties) after receiving SignalR events to reflect changes in the UI.

How can I handle real-time updates using SignalR without reloading the entire Gantt Chart?

Instead of rebinding the entire data source, update only the affected task (insert/update/delete) using Gantt APIs. This avoids performance issues and flickering, especially in large datasets. SignalR events should carry minimal payloads (only changed records) to perform partial updates efficiently.

What is the best way to manage concurrent updates from multiple users in a Gantt Chart using SignalR?

You should handle concurrency on the server side (either the SignalR hub or the backend). Implement conflict-resolution strategies, such as timestamps/versioning or locking mechanisms. The Gantt chart itself does not manage conflicts, so you must ensure consistent updates before broadcasting them to all clients.

Harness the power of Syncfusion’s feature-rich and powerful Angular UI components.

Turn your Angular Gantt Chart into a shared, real-time workspace with SignalR

Once multiple users start interacting with the same timeline, real-time sync stops being optional; it becomes the difference between data you trust and data you constantly double-check.

By integrating SignalR with the Gantt Chart, you move from a static snapshot to an event-driven system. Updates propagate instantly, every client stays in sync, and the UI reflects the actual state instead of lagging behind it.

At its core, this is a shift from pull-based updates (polling and refresh) to push-based communication. That change alone removes a large number of synchronization issues common in multi-user apps.

From here, you can extend the setup: persist changes, scope updates to users or teams, or refine how events are triggered. But even at this level, it solves one of the most persistent problems in collaborative workflows: stale, inconsistent data.

If you’re already using the Syncfusion Angular Gantt Chart, this approach integrates naturally into your existing setup. You can access the implementation through the license and downloads page or explore it using the free 30-day trial.

For any questions or deeper exploration, the support forum, support portal, and feedback portal are available to help you get the most out of your implementation.

Be the first to get updates

Lokesh ArjunanLokesh Arjunan profile icon

Meet the Author

Lokesh Arjunan

Lokesh Arjunan has been a software developer at Syncfusion since January 2020, dedicated to delivering dependable, user‑centric solutions. He brings versatile technical abilities, strong analytical thinking, and a commitment to quality, along with a continuous drive to learn, adapt, and contribute effectively in modern software development environments.

Leave a comment