HelpBot Assistant

How can I help you?

Splitting and Merging Tasks in React Gantt Chart Component

3 Feb 202620 minutes to read

Splitting and merging tasks in the React Gantt Chart component enhances project management by allowing tasks to be divided into segments or recombined, representing breaks or continuous work periods. Split tasks at load time using taskFields.segments for hierarchical data or taskFields.segmentId for self-referential data, ensuring segments fit within the task’s start and end dates. Dynamically split tasks via the dialog’s Segments tab or context menu’s Split Task option, requiring Edit and valid taskFields mappings. Merge tasks using the context menu’s Merge Task option or by dragging segments together in the UI, with enableContextMenu and ContextMenuService enabled. Ensure tasks have sufficient width relative to the timeline unit and are not parent or milestone tasks to enable splitting, and avoid using split tasks with multi-taskbar features to maintain compatibility.

Split tasks at load time

Define task segments at load time using taskFields.segments or taskFields.segmentId mapped. This splits tasks into segments within their original start and end dates, ideal for representing interruptions like holidays in a project schedule.

For more details, see Split task at load time.

Split tasks dynamically

Split tasks dynamically using the dialog or context menu, requiring taskFields.segments or taskFields.segmentId mapped, Edit injected, and editSettings.allowEditing enabled:

  • Dialog: The Segments tab in the add/edit dialog allows splitting tasks based on their start and end dates.
  • Context Menu: Enable enableContextMenu and inject ContextMenuService to include the Split Task option in the context menu, enabling task splitting with a right-click.
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {
    GanttComponent,
    Inject,
    Edit,
    Toolbar,
    Selection,
    ContextMenu,
} from '@syncfusion/ej2-react-gantt';
import { ganttData } from './datasource';

function App() {

    const taskSettings = {
        id: 'TaskID',
        name: 'TaskName',
        startDate: 'StartDate',
        endDate: 'EndDate',
        duration: 'Duration',
        progress: 'Progress',
        parentID: 'ParentID',
        segments: 'Segments'
    };

    const editSettings = {
        allowAdding: true,
        allowEditing: true,
        allowDeleting: true
    };

    const toolbarItems = [
        'Add', 'Edit', 'Update', 'Delete',
        'Cancel', 'ExpandAll', 'CollapseAll'
    ];

    return (
        <GanttComponent
            height="450px"
            dataSource={ganttData}
            taskFields={taskSettings}
            editSettings={editSettings}
            toolbar={toolbarItems}
            enableContextMenu={true}
        >
            <Inject services={[Edit, Toolbar, Selection, ContextMenu]} />
        </GanttComponent>
    );
}

ReactDOM.render(<App />, document.getElementById('root'));
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {
    GanttComponent,
    Inject,
    Edit,
    Toolbar,
    Selection,
    ContextMenu,
    TaskFieldsModel,
    EditSettingsModel
} from '@syncfusion/ej2-react-gantt';
import { ganttData } from './datasource';

function App() {

    const taskSettings: TaskFieldsModel = {
        id: 'TaskID',
        name: 'TaskName',
        startDate: 'StartDate',
        endDate: 'EndDate',
        duration: 'Duration',
        progress: 'Progress',
        parentID: 'ParentID',
        segments: 'Segments'
    };

    const editSettings: EditSettingsModel = {
        allowAdding: true,
        allowEditing: true,
        allowDeleting: true
    };

    const toolbarItems: string[] = [
        'Add', 'Edit', 'Update', 'Delete',
        'Cancel', 'ExpandAll', 'CollapseAll'
    ];

    return (
        <GanttComponent
            height="450px"
            dataSource={ganttData}
            taskFields={taskSettings}
            editSettings={editSettings}
            toolbar={toolbarItems}
            enableContextMenu={true}
        >
            <Inject services={[Edit, Toolbar, Selection, ContextMenu]} />
        </GanttComponent>
    );
}

ReactDOM.render(<App />, document.getElementById('root'));
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Syncfusion React Gantt</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Essential JS 2 for React Components" />
    <meta name="author" content="Syncfusion" />
    <link href="https://cdn.syncfusion.com/ej2/32.2.3/tailwind3.css" rel="stylesheet" type="text/css"/>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
     <style>
        #loader {
            color: #008cff;
            height: 40px;
            left: 45%;
            position: absolute;
            top: 45%;
            width: 30%;
        }
    </style>
<script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.js" type ="text/javascript"></script>
</head>

<body>
        <div id='root'>
            <div id='loader'>Loading....</div>
        </div>
</body>

</html>

Merge tasks dynamically

Merge split tasks using the context menu’s Merge Task option, requiring enableContextMenu and ContextMenuService, or by dragging segments together in the UI. This recombines segments into a single task, ensuring continuity in the project timeline, with Edit and valid taskFields mappings required.

Get the clicked segment information

You can get the clicked segment information using the onTaskbarClick event.

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {
    GanttComponent,
    Inject,
    Edit,
    Toolbar,
    Selection,
    ContextMenu,
} from '@syncfusion/ej2-react-gantt';
import { ganttData } from './datasource';

function App() {
    let message = '';
    const taskSettings = {
        id: 'TaskID',
        name: 'TaskName',
        startDate: 'StartDate',
        endDate: 'EndDate',
        duration: 'Duration',
        progress: 'Progress',
        parentID: 'ParentID',
        segments: 'Segments'
    };
    const editSettings = {
        allowAdding: true,
        allowEditing: true,
        allowDeleting: true
    };
    const toolbarItems = [
        'Add', 'Edit', 'Update', 'Delete',
        'Cancel', 'ExpandAll', 'CollapseAll'
    ];

    function onTaskbarClick(args) {
        const element = args.taskbarElement;
        const indexAttr = element.getAttribute('data-segment-index');

        if (indexAttr === null || indexAttr === undefined) {
            message = 'Task clicked (not a segment)';
            document.getElementById('message').innerText = message;
            return;
        }

        const index = Number(indexAttr);
        const segments = args.data.ganttProperties.segments;
        const segment = segments[index];
        message = `Segment ${segment.segmentIndex} clicked`;

        document.getElementById('message').innerText = message;
    }
    return (
        <div>
            <div id="message" style=>

            </div>

            <GanttComponent
                height="450px"
                dataSource={ganttData}
                taskFields={taskSettings}
                editSettings={editSettings}
                toolbar={toolbarItems}
                enableContextMenu={true}
                onTaskbarClick={onTaskbarClick}
            >
                <Inject services={[Edit, Toolbar, Selection, ContextMenu]} />
            </GanttComponent>
        </div>
    );
}

ReactDOM.render(<App />, document.getElementById('root'));
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {
    GanttComponent,
    Inject,
    Edit,
    Toolbar,
    Selection,
    ContextMenu,
    TaskFieldsModel,
    EditSettingsModel,
    ITaskbarClickEventArgs
} from '@syncfusion/ej2-react-gantt';
import { ganttData } from './datasource';

function App() {
    let message: string = '';
    const taskSettings: TaskFieldsModel = {
        id: 'TaskID',
        name: 'TaskName',
        startDate: 'StartDate',
        endDate: 'EndDate',
        duration: 'Duration',
        progress: 'Progress',
        parentID: 'ParentID',
        segments: 'Segments'
    };
    const editSettings: EditSettingsModel = {
        allowAdding: true,
        allowEditing: true,
        allowDeleting: true
    };
    const toolbarItems: string[] = [
        'Add', 'Edit', 'Update', 'Delete',
        'Cancel', 'ExpandAll', 'CollapseAll'
    ];


    function onTaskbarClick(args: ITaskbarClickEventArgs): void {
        const element = args.taskbarElement as HTMLElement;
        const indexAttr = element.getAttribute('data-segment-index');

        if (indexAttr === null || indexAttr === undefined) {
            message = 'Task clicked (not a segment)';
            document.getElementById('message')!.innerText = message;
            return;
        }

        const index = Number(indexAttr);
        const segments = args.data.ganttProperties.segments;
        const segment = segments[index];
        message = `Segment ${segment.segmentIndex} clicked`;

        document.getElementById('message')!.innerText = message;
    }

    return (
        <div>
            <div id="message" style=>

            </div>

            <GanttComponent
                height="450px"
                dataSource={ganttData}
                taskFields={taskSettings}
                editSettings={editSettings}
                toolbar={toolbarItems}
                enableContextMenu={true}
                onTaskbarClick={onTaskbarClick}
            >
                <Inject services={[Edit, Toolbar, Selection, ContextMenu]} />
            </GanttComponent>
        </div>
    );
}

ReactDOM.render(<App />, document.getElementById('root'));
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Syncfusion React Gantt</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Essential JS 2 for React Components" />
    <meta name="author" content="Syncfusion" />
    <link href="https://cdn.syncfusion.com/ej2/32.2.3/tailwind3.css" rel="stylesheet" type="text/css"/>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
     <style>
        #loader {
            color: #008cff;
            height: 40px;
            left: 45%;
            position: absolute;
            top: 45%;
            width: 30%;
        }
    </style>
<script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.js" type ="text/javascript"></script>
</head>

<body>
        <div id='root'>
            <div id='loader'>Loading....</div>
        </div>
</body>

</html>

Limitations of Split tasks

  1. Parent and milestone tasks cannot be split into segments.
  2. The task must have a width greater than the timeline unit cell in order to be split.
  3. Split task is not supported with Multi taskbar.

See also