Task Management

ApexGantt exposes a programmatic CRUD API for adding, updating, deleting, and re-parenting tasks after the chart has rendered. Every mutation method is recorded in the undo history, so users can reverse any change without extra wiring on your part.


Adding tasks

Use addTask(input, options?) to insert a new task and trigger a re-render.

const gantt = new ApexGantt(document.querySelector('#chart'), { series: [] })
gantt.render()

// Add a top-level task
gantt.addTask({
  id: 'review',
  name: 'Review',
  startTime: '2024-08-01',
  endTime: '2024-08-05'
})

To place a task inside an existing parent, pass its id in the second argument:

// Insert as a child of an existing task
gantt.addTask(
  {
    id: 'sub-1',
    name: 'Subtask',
    startTime: '2024-08-01',
    endTime: '2024-08-03'
  },
  { parentId: 'review-phase' }
)

What to expect:

  • The method returns the inserted Task object on success.
  • It returns null if a beforeTaskAdd lifecycle hook cancelled the insertion.
  • It throws if the supplied id already exists in the chart.

Updating tasks

Use updateTask(taskId, updatedTask) to apply a partial update to an existing task. You only need to supply the fields you want to change; everything else is left untouched.

// Mark a task as complete
gantt.updateTask('task-3', { progress: 100 })

// Shift the scheduled dates
gantt.updateTask('task-3', { startTime: '2024-09-01', endTime: '2024-09-15' })

// Rename the task
gantt.updateTask('task-3', { name: 'Final Review' })

The chart updates the relevant rows without performing a full re-render, so the operation is efficient even for large task trees.

updateTask throws if the taskId does not match any task in the current dataset. Validate the id before calling if the source is dynamic.


Deleting tasks

Use deleteTask(taskId, options?) to remove a task and re-render.

// Remove a leaf task (no children)
gantt.deleteTask('task-5')

The method returns true when the task is removed, or false when a beforeTaskDelete hook cancelled the operation.

Cascade modes

When a task has children, you must decide what happens to them. Pass a cascade option to control this.

ModeBehaviorWhen to use
'forbid' (default)Throws if the task has childrenPrevents accidental bulk deletion
'children'Deletes the task and all its descendants in one undoable transactionRemoving an entire phase or subtree
'orphan'Moves the task's immediate children up to the deleted task's parent (or root), then removes the taskFlattening a hierarchy without losing work
// Remove a parent and all its descendants
gantt.deleteTask('phase-1', { cascade: 'children' })

// Remove a parent but keep its children (they move up one level)
gantt.deleteTask('phase-1', { cascade: 'orphan' })

Any dependency edges that referenced the deleted task are removed in the same transaction. You do not need to clean up arrows manually.


Moving tasks (re-parenting)

Use moveTask(taskId, options?) to change a task's parent without altering its other properties.

// Move task-5 under a different phase
gantt.moveTask('task-5', { newParentId: 'phase-2' })

// Promote task-5 to the root level
gantt.moveTask('task-5', { newParentId: null })

Pass newParentId: null to move a task to the root of the hierarchy.

The operation is recorded in the undo history. If the move would create a cycle (for example, moving a parent into one of its own descendants), moveTask throws rather than producing an invalid tree.


Milestones

Set type: 'milestone' on a task to render it as a diamond on the timeline instead of a bar. Milestones represent a point in time rather than a duration, so you can set startTime and endTime to the same date.

gantt.addTask({
  id: 'go-live',
  name: 'Go Live',
  type: 'milestone',
  startTime: '2024-09-30',
  endTime: '2024-09-30'
})

The three task type values are:

  • 'task' (default): a standard bar spanning the duration.
  • 'milestone': a diamond rendered at a single date.
  • 'summary': an auto-computed rollup bar. ApexGantt sets this automatically for rows that have children; you rarely need to set it manually.

You can also update an existing task's type:

gantt.updateTask('go-live', { type: 'milestone' })

Lifecycle hooks

Lifecycle hooks let you validate or cancel CRUD operations before they take effect. Register them in the GanttUserOptions when you construct the chart.

const gantt = new ApexGantt(document.querySelector('#chart'), {
  series: tasks,

  beforeTaskAdd: ({ task }) => {
    // Reject tasks without a name
    if (!task.name || task.name.trim() === '') {
      alert('A task must have a name.')
      return false
    }
  },

  beforeTaskDelete: ({ task }) => {
    // Ask the user before deleting an in-progress task
    if (task.progress > 0 && task.progress < 100) {
      return confirm(`"${task.name}" is still in progress. Delete anyway?`)
    }
  },

  beforeTaskUpdate: ({ updates }) => {
    // Reject out-of-range progress values
    if (updates.progress !== undefined && updates.progress > 100) {
      return false
    }
  },

  beforeTaskMove: ({ taskId, newParentId }) => {
    // Prevent moving tasks into a locked phase
    if (lockedPhaseIds.has(newParentId)) {
      return false
    }
  }
})

How hooks work:

  • Return false (or a promise that resolves to false) to cancel the operation. The chart state does not change and nothing is written to the undo history.
  • Return true, undefined, or anything other than false to allow the operation to proceed.
  • All hooks can be async. ApexGantt awaits the return value before continuing.

The context object passed to each hook contains the relevant task data. For beforeTaskAdd this is the input you provided. For beforeTaskDelete and beforeTaskMove this includes the current task from the chart's data. For beforeTaskUpdate this includes taskId and the partial updates object.


Selection API

ApexGantt includes a selection API for reading and controlling which tasks are highlighted. Enable it with the enableSelection option:

const gantt = new ApexGantt(document.querySelector('#chart'), {
  series: tasks,
  enableSelection: true
})
gantt.render()

Then use these methods at any point after rendering:

// Read the currently selected task ids
const selected = gantt.getSelectedTasks()
console.log(selected) // ['task-1', 'task-3']

// Programmatically select specific tasks
gantt.setSelectedTasks(['task-1', 'task-3'])

// Clear all selections
gantt.clearSelection()

setSelectedTasks is useful when you want to sync the chart's selection with an external list or table. For example, if a user clicks a task name in a sidebar, call setSelectedTasks with that id to highlight the corresponding row in the chart.