Our flexible Kanban board for managing tasks with drag drop


Post by cenum »

Hello,
I would like to integrate the tagCombo into the Taskboard component. Here is the configuration of my component:

"use client";
import { Store } from "@bryntum/taskboard";
import { BryntumTaskBoard } from "@bryntum/taskboard-react";
import { useRef, useState } from "react";

export default function Taskboard() {
  const tagsStore = new Store({
    data: [
      { id: "/api/tags/1", title: "tag 01" },
      { id: "/api/tags/2", title: "tag 02" },
      { id: "/api/tags/3", title: "tag 03" },
      { id: "/api/tags/4", title: "tag 04" },
    ],
  });

  const [taskboard] = useState({
    useDomTransition: true,

columnField: "columns",
taskDragFeature: true,
columnToolbarsFeature: true,
columnRenameFeature: true,

taskEditFeature: {
  items: {
    tags: {
      type: "tagCombo",
      label: "tag",
      name: "tags",
      displayField: "title",
      valueField: null,
      store: tagsStore,
    },
  },
},

footerItems: {
  tags: { type: "tags", textProperty: "title" },
},

project: {
  transport: {
    load: {
      url: "apidata.json",
    },
  },
  autoLoad: true,
},
  });

  const taskBoardRef = useRef(null);

  return (
    <>
      <BryntumTaskBoard ref={taskBoardRef} {...taskboard} />
    </>
  );
}

The model data comes from my REST API.

{
  "success": true,
  "tasks": {
    "rows": [
      {
        "name": "Tache 01",
        "direction": null,
        "note": null,
        "readOnly": null,
        "eventColor": "teal",
        "constraintDate": null,
        "constraintType": null,
        "deadlineDate": null,
        "duration": null,
        "durationUnit": "day",
        "effort": null,
        "effortDriven": null,
        "effortUnit": null,
        "endDate": "2025-06-19T00:00:00+02:00",
        "ignoreResourceCalendar": null,
        "inactive": null,
        "manuallyScheduled": null,
        "percentDone": null,
        "projectConstraintResolution": null,
        "schedulingMode": null,
        "slackUnit": null,
        "startDate": "2025-06-03T00:00:00+02:00",
        "unscheduled": false,
        "cls": "",
        "iconCls": null,
        "style": null,
        "taskIconCls": null,
        "expanded": null,
        "parentIndex": 0,
        "orderedParentIndex": null,
        "status": null,
        "weight": 100,
        "prio": null,
        "draggable": null,
        "resizable": null,
        "allDay": false,
        "recurrenceRule": null,
        "milestoneWidth": null,
        "stickyContents": null,
        "id": "/api/tasks/19",
        "columns": "/api/columns/19",
        "tags": [
          { "id": "/api/tags/1", "title": "tag 01" },
          { "id": "/api/tags/2", "title": "tag 02" }
        ]
      },
      {
        "name": "Tache 02",
        "direction": null,
        "note": null,
        "readOnly": null,
        "eventColor": "magenta",
        "constraintDate": null,
        "constraintType": null,
        "deadlineDate": null,
        "duration": null,
        "durationUnit": "day",
        "effort": null,
        "effortDriven": null,
        "effortUnit": null,
        "endDate": "2025-07-04T00:00:00+02:00",
        "ignoreResourceCalendar": null,
        "inactive": false,
        "manuallyScheduled": null,
        "percentDone": null,
        "projectConstraintResolution": null,
        "schedulingMode": null,
        "slackUnit": null,
        "startDate": "2025-06-03T00:00:00+02:00",
        "unscheduled": false,
        "cls": "",
        "iconCls": null,
        "style": null,
        "taskIconCls": null,
        "expanded": null,
        "parentIndex": 1,
        "orderedParentIndex": null,
        "status": null,
        "weight": 100,
        "prio": null,
        "draggable": null,
        "resizable": null,
        "allDay": false,
        "recurrenceRule": null,
        "milestoneWidth": null,
        "stickyContents": null,
        "id": "/api/tasks/20",
        "columns": "/api/columns/20"
      }
    ]
  },
  "calendars": {
    "rows": [
      {
        "readOnly": null,
        "cls": null,
        "iconCls": null,
        "ignoreTimeZone": null,
        "name": "général",
        "treatInconsistentIntervals": null,
        "unspecifiedTimeIsWorking": true,
        "expanded": null,
        "intervals": [
          {
            "id": 1,
            "readOnly": null,
            "cls": null,
            "compositeCode": null,
            "iconCls": null,
            "priority": null,
            "recurrentEndDate": "on Mon",
            "recurrentStartDate": "on Sat",
            "startDate": null,
            "endDate": null,
            "type": null,
            "expanded": null
          }
        ],
        "id": "/api/calendars/2"
      }
    ]
  },
  "columns": {
    "rows": [
      {
        "readOnly": null,
        "collapsed": null,
        "collapsible": null,
        "color": null,
        "flex": null,
        "hidden": null,
        "htmlEncodeHeaderText": null,
        "minWidth": null,
        "tasksPerRow": null,
        "text": "column #1",
        "tooltip": null,
        "width": null,
        "expanded": null,
        "id": "/api/columns/19"
      },
      {
        "readOnly": null,
        "collapsed": null,
        "collapsible": null,
        "color": null,
        "flex": null,
        "hidden": null,
        "htmlEncodeHeaderText": null,
        "minWidth": null,
        "tasksPerRow": null,
        "text": "Column #2",
        "tooltip": null,
        "width": null,
        "expanded": null,
        "id": "/api/columns/20"
      },
      {
        "readOnly": null,
        "collapsed": null,
        "collapsible": null,
        "color": null,
        "flex": null,
        "hidden": null,
        "htmlEncodeHeaderText": null,
        "minWidth": null,
        "tasksPerRow": null,
        "text": "Column #2",
        "tooltip": null,
        "width": null,
        "expanded": null,
        "id": "/api/columns/30"
      },
      {
        "readOnly": null,
        "collapsed": null,
        "collapsible": null,
        "color": null,
        "flex": null,
        "hidden": null,
        "htmlEncodeHeaderText": null,
        "minWidth": null,
        "tasksPerRow": null,
        "text": "Column #3",
        "tooltip": null,
        "width": null,
        "expanded": null,
        "id": "/api/columns/31"
      }
    ]
  }
}

The issue comes from the fact that the component doesn't recognize the default values it receives from the data.

Capture d’écran 2025-06-16 171154.jpg
Capture d’écran 2025-06-16 171154.jpg (58.39 KiB) Viewed 20732 times

Thanks in advance for your help!


Post by marcio »

Hey cenum,

Thanks for reaching out.

Since your tags are stored as objects with id and title, you should ensure that the valueField is set correctly to match the structure of your data.

In your TagCombo configuration, you have set valueField: null. This should be set to the field that uniquely identifies each tag, which in your case appears to be id. Here's how you can adjust your configuration:

taskEditFeature: {
  items: {
    tags: {
      type: "tagCombo",
      label: "tag",
      name: "tags",
      displayField: "title",
      valueField: "id", // Set this to the field that identifies the tag
      store: tagsStore,
    },
  },
},

Make sure that the tags field in your task data is an array of tag ids, not objects. If your data structure is different, you might need to adjust how the tags are stored or retrieved.

If the issue persists, please provide more details about how the tags are being set and used in your application.

Best regards,
Márcio

How to ask for help? Please read our Support Policy


Post by cenum »

Thanks for your response. I applied the changes to the tagCombo config, but the issue now is that the tags item in the body shows the tag IDs instead of their titles.

{
  "success": true,
  "tasks": {
    "rows": [
      {
        "name": "Tache 01",
        "direction": null,
        "note": null,
        "readOnly": null,
        "eventColor": "teal",
        "constraintDate": null,
        "constraintType": null,
        "deadlineDate": null,
        "duration": null,
        "durationUnit": "day",
        "effort": null,
        "effortDriven": null,
        "effortUnit": null,
        "endDate": "2025-06-19T00:00:00+02:00",
        "ignoreResourceCalendar": null,
        "inactive": null,
        "manuallyScheduled": null,
        "percentDone": null,
        "projectConstraintResolution": null,
        "schedulingMode": null,
        "slackUnit": null,
        "startDate": "2025-06-03T00:00:00+02:00",
        "unscheduled": false,
        "cls": "",
        "iconCls": null,
        "style": null,
        "taskIconCls": null,
        "expanded": null,
        "parentIndex": 0,
        "orderedParentIndex": null,
        "status": null,
        "weight": 100,
        "prio": null,
        "draggable": null,
        "resizable": null,
        "allDay": false,
        "recurrenceRule": null,
        "milestoneWidth": null,
        "stickyContents": null,
        "id": "/api/tasks/19",
        "columns": "/api/columns/19",
        "tags": ["/api/tags/1", "/api/tags/2"]
      },
      {
        "name": "Tache 02",
        "direction": null,
        "note": null,
        "readOnly": null,
        "eventColor": "magenta",
        "constraintDate": null,
        "constraintType": null,
        "deadlineDate": null,
        "duration": null,
        "durationUnit": "day",
        "effort": null,
        "effortDriven": null,
        "effortUnit": null,
        "endDate": "2025-07-04T00:00:00+02:00",
        "ignoreResourceCalendar": null,
        "inactive": false,
        "manuallyScheduled": null,
        "percentDone": null,
        "projectConstraintResolution": null,
        "schedulingMode": null,
        "slackUnit": null,
        "startDate": "2025-06-03T00:00:00+02:00",
        "unscheduled": false,
        "cls": "",
        "iconCls": null,
        "style": null,
        "taskIconCls": null,
        "expanded": null,
        "parentIndex": 1,
        "orderedParentIndex": null,
        "status": null,
        "weight": 100,
        "prio": null,
        "draggable": null,
        "resizable": null,
        "allDay": false,
        "recurrenceRule": null,
        "milestoneWidth": null,
        "stickyContents": null,
        "id": "/api/tasks/20",
        "columns": "/api/columns/20"
      }
    ]
  },
  "calendars": {
    "rows": [
      {
        "readOnly": null,
        "cls": null,
        "iconCls": null,
        "ignoreTimeZone": null,
        "name": "général",
        "treatInconsistentIntervals": null,
        "unspecifiedTimeIsWorking": true,
        "expanded": null,
        "intervals": [
          {
            "id": 1,
            "readOnly": null,
            "cls": null,
            "compositeCode": null,
            "iconCls": null,
            "priority": null,
            "recurrentEndDate": "on Mon",
            "recurrentStartDate": "on Sat",
            "startDate": null,
            "endDate": null,
            "type": null,
            "expanded": null
          }
        ],
        "id": "/api/calendars/2"
      }
    ]
  },
  "columns": {
    "rows": [
      {
        "readOnly": null,
        "collapsed": null,
        "collapsible": null,
        "color": null,
        "flex": null,
        "hidden": null,
        "htmlEncodeHeaderText": null,
        "minWidth": null,
        "tasksPerRow": null,
        "text": "column #1",
        "tooltip": null,
        "width": null,
        "expanded": null,
        "id": "/api/columns/19"
      },
      {
        "readOnly": null,
        "collapsed": null,
        "collapsible": null,
        "color": null,
        "flex": null,
        "hidden": null,
        "htmlEncodeHeaderText": null,
        "minWidth": null,
        "tasksPerRow": null,
        "text": "Column #2",
        "tooltip": null,
        "width": null,
        "expanded": null,
        "id": "/api/columns/20"
      },
      {
        "readOnly": null,
        "collapsed": null,
        "collapsible": null,
        "color": null,
        "flex": null,
        "hidden": null,
        "htmlEncodeHeaderText": null,
        "minWidth": null,
        "tasksPerRow": null,
        "text": "Column #2",
        "tooltip": null,
        "width": null,
        "expanded": null,
        "id": "/api/columns/30"
      },
      {
        "readOnly": null,
        "collapsed": null,
        "collapsible": null,
        "color": null,
        "flex": null,
        "hidden": null,
        "htmlEncodeHeaderText": null,
        "minWidth": null,
        "tasksPerRow": null,
        "text": "Column #3",
        "tooltip": null,
        "width": null,
        "expanded": null,
        "id": "/api/columns/31"
      }
    ]
  }
}

Capture d’écran 2025-06-17 091005.jpg
Capture d’écran 2025-06-17 091005.jpg (60.04 KiB) Viewed 20709 times

Thanks


Post by tasnim »

You'd need to set displayField https://bryntum.com/products/taskboard/docs/api/TaskBoard/widget/TagCombo#config-displayField for that. Have you set the displayField to the field that you want to show in the list?
If you still face the issue, please share a test case based on this codepen https://codepen.io/dv-auntik/pen/EajejYP?editors=101

Best regards,
Tasnim

How to ask for help? Please read our Support Policy


Post by cenum »

You can find my code in the provided CodePen link.
https://codepen.io/Borkil-the-typescripter/pen/MYwqJQE
As you can see, the TagCombo is working correctly and data loads as expected.
The issue occurs when selecting a different tag: the TagCombo only returns the ID (or an array of IDs), which causes the task body to lose access to the full tag object and display incorrectly.


Post by tasnim »

You'd need to set the valueField to null so it will return the whole record for it as described in the docs here https://bryntum.com/products/taskboard/docs/api/TaskBoard/widget/TagCombo#config-valueField

Here is the updated codepen https://codepen.io/dv-auntik/pen/LEVJWYw?editors=0010

Best regards,
Tasnim

How to ask for help? Please read our Support Policy


Post by cenum »

you're replacing my array of tag objects with items from the tagsStore.

How can I handle this dynamically?
My API sometimes returns full objects, and sometimes just an array of IDs.
What’s the recommended way to support both formats without breaking the task display?


Post by tasnim »

I've updated the CodePen for you according to your requirement here https://codepen.io/dv-auntik/pen/LEVJWYw?editors=0010

Best regards,
Tasnim

How to ask for help? Please read our Support Policy


Post Reply