Copy and Paste Records in React Gantt Chart Component

18 Nov 201812 minutes to read

The copy and paste functionality in the React Gantt Chart component enables efficient task duplication, allowing you to replicate tasks or entire task hierarchies using the addRecord method and a custom context menu configured via contextMenuItems. For example, right-clicking a parent task to copy and paste it with its child tasks at a specified position streamlines project management workflows. Inject Edit service and enable editSettings.allowAdding to support adding copied records. Define valid taskFields mappings (e.g., id, name, startDate) to ensure task data is correctly replicated, including hierarchical structures with child tasks. Use the contextMenuClick event to handle custom copy-paste actions, specifying the paste position (e.g., child, above, below) via addRecord parameters. This feature integrates with dependencies, critical path, and virtual scrolling, ensuring duplicated tasks align with the project structure for seamless schedule management.

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

function App() {

  let ganttInstance = null;
  let copiedRecord = null;
  const taskSettings = {
    id: "TaskID",
    name: "TaskName",
    startDate: "StartDate",
    duration: "Duration",
    progress: "Progress",
    dependency: "Predecessor",
    parentID: "ParentID"
  };

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

  const contextMenuItems = [
    { text: "Copy", target: ".e-content", id: "copy" },
    { text: "Paste", target: ".e-content", id: "paste" }
  ];

  function contextMenuClick(args) {
    if (args.item.id === "copy") {
      copiedRecord = args.rowData;
      copiedRecord.taskData.TaskID =
        ganttInstance.currentViewData.length + 1;
    }

    if (args.item.id === "paste") {
      ganttInstance.addRecord(
        copiedRecord.taskData,
        "Below",
        args.rowData.index
      );

      if (copiedRecord.hasChildRecords) {
        addChildRecords(copiedRecord, args.rowData.index + 1);
      }

      copiedRecord = null;
    }
  }

  function contextMenuOpen(args) {
    if (args.type !== "Header") {
      if (copiedRecord) {
        args.hideItems.push("Copy");
      } else {
        args.hideItems.push("Paste");
      }
    }
  }

  function addChildRecords(record, index) {
    for (let i = 0; i < record.childRecords.length; i++) {
      const childRecord = record.childRecords[i];
      childRecord.taskData.TaskID =
        ganttInstance.currentViewData.length + 1;

      ganttInstance.addRecord(childRecord.taskData, "Child", index);

      if (childRecord.hasChildRecords) {
        addChildRecords(childRecord, index + (i + 1));
      }
    }
  }

  return (
    <GanttComponent
      height="430px"
      dataSource={taskData}
      taskFields={taskSettings}
      editSettings={editSettings}
      enableContextMenu={true}
      contextMenuItems={contextMenuItems}
      contextMenuClick={contextMenuClick}
      contextMenuOpen={contextMenuOpen}
      ref={(g) => (ganttInstance = g)}
    >
      <Inject services={[Selection, ContextMenu, Edit]} />
    </GanttComponent>
  );
}

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

function App() {

  let ganttInstance: GanttComponent | null = null;
  let copiedRecord: any = null;

  const data: object[] = taskData;

  const taskSettings: TaskFieldsModel = {
    id: "TaskID",
    name: "TaskName",
    startDate: "StartDate",
    duration: "Duration",
    progress: "Progress",
    dependency: "Predecessor",
    parentID: "ParentID"
  };

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

  const contextMenuItems: any[] = [
    { text: "Copy", target: ".e-content", id: "copy" },
    { text: "Paste", target: ".e-content", id: "paste" }
  ];

  function contextMenuClick(args: ContextMenuClickEventArgs): void {
    if (args.item.id === "copy") {
      copiedRecord = args.rowData;
      copiedRecord.taskData.TaskID =
        ganttInstance!.currentViewData.length + 1;
    }

    if (args.item.id === "paste") {
      ganttInstance!.addRecord(
        copiedRecord.taskData,
        "Below",
        args.rowData!.index
      );

      if (copiedRecord.hasChildRecords) {
        addChildRecords(copiedRecord, args.rowData!.index! + 1);
      }

      copiedRecord = null;
    }
  }

  function contextMenuOpen(args: ContextMenuOpenEventArgs): void {
    if (args.type !== "Header") {
      if (copiedRecord) {
        args.hideItems!.push("Copy");
      } else {
        args.hideItems!.push("Paste");
      }
    }
  }

  function addChildRecords(record: any, index: number): void {
    for (let i = 0; i < record.childRecords.length; i++) {
      const childRecord = record.childRecords[i];
      childRecord.taskData.TaskID =
        ganttInstance!.currentViewData.length + 1;

      ganttInstance!.addRecord(childRecord.taskData, "Child", index);

      if (childRecord.hasChildRecords) {
        addChildRecords(childRecord, index + (i + 1));
      }
    }
  }

  return (
    <GanttComponent
      height="430px"
      dataSource={data}
      taskFields={taskSettings}
      editSettings={editSettings}
      enableContextMenu={true}
      contextMenuItems={contextMenuItems}
      contextMenuClick={contextMenuClick}
      contextMenuOpen={contextMenuOpen}
      ref={(g) => (ganttInstance = g)}
    >
      <Inject services={[Selection, ContextMenu, Edit]} />
    </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/34.1.29/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>
</head>

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

</html>

See also