Our state of the art Gantt chart


Post by bala24 »

Hi Team,

Continuing with updating gantt chart, I have initialised the gantt component with column configuration having custom renderer. It worked fine on first render. However, after any re-render (the parent component updates) and there is no data update on the props sent to Gantt component, the expand collapse disappears. I'm not able to figure out why it does so. The data is same. I have attached the code with data and screen shots capturing the two states.

Any insights will be helpful.

Thanks,
Bala.

// Define the custom properties
interface CustomModelProps {
    taskType?: "step" | "stage"
    description?: string
  }

type CustomModel = Model & CustomModelProps

const MyGanttView = () => {
    const ganttRef = useRef(null)
    const tasks = [{
        "id": 0,
        "name": "Parent - 1",
        "startDate": "2024-08-13T09:00:00+05:30",
        "endDate": "2024-08-14T09:00:00+05:30",
        "expanded": true,
        "children": [
            {
                "id": "019122d7-9ffa-75b1-9c42-82d5d734221f",
                "name": "Child - 1",
                "startDate": "2024-08-14T09:00:00+05:30",
                "duration": 0,
                "rollup": true,
                "taskType": "step",
                "description": "---description - child - 1---"
            },
            {
                "id": "019122d7-9ffa-75b1-9c42-82e8b76301e9",
                "name": "Child - 2",
                "startDate": "2024-08-14T09:00:00+05:30",
                "duration": 0,
                "rollup": true,
                "taskType": "step",
                "description": "---description -child-2 ---"
            }
        ],
        "cls": "stage-container",
        "taskType": "stage",
        "description": "---description text---"
    },
    {
        "id": 1,
        "name": "Parent - 2",
        "startDate": "2024-08-14T11:30:00+05:30",
        "endDate": "2024-08-14T17:00:00+05:30",
        "expanded": true,
        "children": [
            {
                "id": "019122d7-9ffa-75b1-9c42-8312bfb02bdf",
                "name": "Child - 1",
                "startDate": "2024-08-14T12:00:00+05:30",
                "duration": 0,
                "rollup": true,
                "taskType": "step",
                "description": "---description text---"
            },
            {
                "id": "019122d7-9ffa-75b1-9c42-832061f3b7fc",
                "name": "Child - 2",
                "startDate": "2024-08-14T17:00:00+05:30",
                "duration": 0,
                "rollup": true,
                "taskType": "step",
                "description": "---description text---"
            }
        ],
        "cls": "stage-container",
        "taskType": "stage",
        "description": "---description text---"
    }]
const ganttConfig = {
    readOnly: true,
    viewPreset: "hourAndDay",
    rowHeight: 60,
    project: {
    autoSetConstraints: true,
    tasks: tasks,
    },
    rollupsFeature: true,
    projectLinesFeature: false,
    eventMenuFeature: false,
    scheduleMenuFeature: false,
    headerMenuFeature: false,
    taskTooltipFeature: false,
    cellEditFeature: false,
    cellMenuFeature: false,
    columnReorderFeature: false,
    taskMenuFeature: false,
    taskEditFeature: false,
    rowReorderFeature: false,
    columnLinesFeature: false,
    columnLines: false,
    rowLinesFeature: false,
    rowLines: false,
    zoomOnTimeAxisDoubleClick: false,
    sortFeature: false,
}
return <BryntumGantt 
    ref={ganttRef} 
    {...ganttConfig} 
    columns={[{
      type: "name",
      field: "name",
      text: "Stages",
      width: 500,
      htmlEncode: false,
      renderer: ({
        record,
        value,
      }: {
        record: CustomModel
        value: string
      }) => {
        if (record?.taskType === "step") {
          return `
            <div class="ml-2 flex gap-2">
              <div class="diamond-container">
                <div class="diamond"></div>
              </div>
              <div class="flex flex-col gap-1">
                <div class="text-sm font-normal">${value}</div>
                <div class="text-sm font-normal text-custom-gray-2">
                  ${record?.description}
                </div>
              </div>
            </div>
          `
        }
        if (record?.taskType === "stage") {
          return `
          <div class="flex gap-2">
            <div class="flex flex-col gap-1">
              <div class="text-sm font-semibold text-black">${value}</div>
              <div class="text-sm font-normal text-custom-gray-2">
                ${record?.description}
              </div>
            </div>
          </div>
          `
        }
        return value
      },
    },
  ]}/>
}
Attachments
re-render-expand-disappears.png
re-render-expand-disappears.png (113.34 KiB) Viewed 341 times
initial-render-with-expand-collapse.png
initial-render-with-expand-collapse.png (110.34 KiB) Viewed 341 times

Post by marcio »

Hey Bala,

Thanks for reaching out and for the example.

I was able to reproduce that and created a ticket to fix it https://github.com/bryntum/support/issues/9768.

Please watch the ticket to receive live updates.

Best regards,
Márcio


Post by bala24 »

Is there any work around for this ? when is it expected to be fixed ?


Post by marcio »

Hey Bala,

We'll have someone on our dev team look into it and check if there is a workaround for now. Until then, we are not able to tell an estimation of a fix.

Best regards,
Márcio


Post by ghulam.ghous »

Hello there,

I got the chance to look at the bug reported above. This is not an issue on our end and instead it is the issue of how you have decalred configs in the component and using them. You have declared a variable for tasks and config and on each re-render, they are re-created and hence their reference changes and gantt component treats them as new configs and recreates each thing. And also you are passing the columns directly to the gantt component which is not supported. We have two adopted practices to handle static and dynamic configs. For static configs, we recommend moving them to static files and import them inside your component. And the configs which are going to be changed at runtime, should be wrapped by a useState or useMemo.

https://bryntum.com/products/gantt/docs/guide/Gantt/integration/react/guide#best-practices-for-configuration-management
For static configs: https://bryntum.com/products/gantt/docs/guide/Gantt/integration/react/guide#external-configuration-for-static-settings
For Dynamic configs: https://bryntum.com/products/gantt/docs/guide/Gantt/integration/react/guide#state-managed-configuration-for-dynamic-settings
Another thing in frameworks, we recommend to using BryntumGanttProjectModel for configuring project on your component.
Please follow these guides and implement your solution accordingly.

I have updated the test case and providing you both version using BryntumGanttProjectModel and with management of static and dynamic configs. See the clip and test cases and let us know if the problem still exists for you. I am also closing the ticket as it is not an issue on our end:

Screen Recording 2024-08-09 at 5.33.47 PM.zip
(2.87 MiB) Downloaded 8 times
basic-example-using-useState.zip
(3.81 MiB) Downloaded 10 times
basic-example-using-static-configs.zip
(3.81 MiB) Downloaded 8 times

Regards,
Ghulam Ghous


Post by bala24 »

I'll try this out and update. Thank you for the suggestions with example.


Post by ghulam.ghous »

We will be waiting for your update. Happy coding :)


Post by bala24 »

This worked. Thanks a lot :)


Post by ghulam.ghous »

That's great to hear. Please don't hesitate to reach out to us if you have any questions in future.


Post Reply