Skip to main content

Editing

This page describes how to edit tasks in chart UI and in the grid area. For the instructions on adding and configuring the Editor component, refer to the Editor section.

Edit tasks in chart UI​

The task editor dialog provides fields for viewing and editing tasks. This section shows how to control which UI operations with tasks should be allowed in Gantt.

Prevent default UI actions​

By default, all actions are enabled, but you can make the widget read-only or selectively block certain operations such as adding tasks, dragging, or creating links.

Gantt API provides an interception mechanism for all user actions.
Every action handler can return:

  • false → blocks the action
  • true or undefined → allows the action to continue

You can use the api.intercept() method to define these rules.

Disable dragging tasks (horizontally on the chart)​

To block horizontal dragging, listen to the drag-task event and check its parameters. This allows you to determine which dimension the drag occurs in — vertical or horizontal. If the drag is horizontal (start/end dates change), you can block it. To block horizontal drag:

api.intercept("drag-task", ev => {
// left position or width has been changed
if (typeof ev.left !== "undefined" || typeof ev.width !== "undefined") return false;
});

Disable reordering tasks (vertically in the grid)​

This works the same way as disabling horizontal dragging, but here we listen specifically for changes to the top parameter. If the top parameter is present, it means a vertical drag occurs (row reordering in the grid), and the action should be blocked.

To block vertical reordering:

api.intercept("drag-task", ev => {
// top position has been changed
if (typeof ev.top !== "undefined") return false;
});

Adding tasks​

If you need to block adding tasks for specific cases (for example, only for certain parent tasks), you can intercept the add-task action:

api.intercept("add-task", ev => {
// don't add children to task with id=4
if(ev.target == 4) return false;
});

If you want to completely disable adding tasks in the UI, remove the column that displays the "+" buttons:

<script setup>
import { Gantt, defaultColumns } from "@svar-ui/vue-gantt";
const columns = defaultColumns.filter(c => c.id !== "add-task");
</script>

<template>
<Gantt :columns="columns" />
</template>

If you need to block creating links only for specific tasks, you can intercept the add-link action:

api.intercept("add-link", ({link}) => {
// don't add links to task with id=4
if(link.source == 4 || link.target == 4)
return false;
});

If you want to completely disable link creation in the UI, hide the link markers using CSS:

<div class="gantt hide-links" >
<Gantt/>
</div>

.gantt.hide-links > :global(.wx-gantt .wx-bar .wx-link) {
display: none;
}

If you need to block deleting links for specific tasks, you can intercept the delete-link action:

api.intercept("delete-link", ({ id }) => {
const links = api.getState().links;
const link = links.byId(id);

// don't delete links from task with id=4
if(link.source == 4 || link.target == 4)
return false;
});

If you want to completely disable link deletion in the UI, hide the delete buttons and disable selectable link behavior using CSS:

<div class="gantt hide-delete-links" >
<Gantt/>
</div>

.gantt.hide-delete-links > :global(.wx-gantt .wx-delete-link) {
display: none;
}
.gantt.hide-delete-links > :global(.wx-gantt .wx-line:hover) {
cursor: default;
stroke: var(--wx-gantt-link-color);
}
.gantt.hide-delete-links > :global(.wx-gantt .wx-line.wx-line-selectable) {
cursor: default;
}

Editing progress in the chart​

If you want to disable editing progress for all tasks, you can hide the progress handle using CSS:

<div class="gantt hide-progress" >
<Gantt/>
</div>

.gantt.hide-progress > :global(.wx-gantt .wx-bar .wx-progress-marker) {
display: none;
}

Related sample: Prevent actions

Add tasks by drag and drop from outside​

If you keep work items in a separate list, for example a backlog, you can let users add one to Gantt by dragging it onto a task. Set draggableRows on a Grid that lists the items, then add three handlers:

1. Start the drag. On dragstart, use locateID (from @svar-ui/lib-dom) to read the id of the row being dragged, get the row object via tableApi.getRow(), and put its id and text on dataTransfer. Also import the locateTask helper, used in the next steps to find the drop target:

import { ref } from "vue";
import { locateID } from "@svar-ui/lib-dom";
import { Grid } from "@svar-ui/vue-grid";
import { Gantt, locateTask } from "@svar-ui/vue-gantt";

const MIME = "application/x-my-task";
const backlog = ref([...backlogTasks]);
const tableApi = ref(null);
let api;

function init(ganttApi) {
api = ganttApi;
}

function onGridDragStart(e) {
const id = locateID(e);
if (id == null || !tableApi.value) return;

const row = tableApi.value.getRow(id);
if (!row) return;

e.dataTransfer.setData(MIME, JSON.stringify(row.id));
e.dataTransfer.setData("text/plain", row.text || "");
e.dataTransfer.effectAllowed = "copy";
}

2. Track the drop target. On dragover, call locateTask to check whether the pointer is over a task:

function onDragOver(e) {
if (!e.dataTransfer.types.includes(MIME)) return;
if (!locateTask(e, api)) return;
e.preventDefault();
e.dataTransfer.dropEffect = "copy";
}

3. Add the task on drop.

On drop:

  • Read the item id back from dataTransfer, and locate the drop target with locateTask.
  • Load the target task via api.getTask() and pick the mode: "child" if the target is a summary, "after" otherwise.
  • Take the start date from that summary, or from the target itself for a top-level task.
  • Create the task with add-task, then remove the item from the list:
function onDrop(e) {
if (!e.dataTransfer.types.includes(MIME) || !api) return;
const taskId = JSON.parse(e.dataTransfer.getData(MIME));
const target = locateTask(e, api);
const item = backlog.value.find(t => t.id === taskId);
if (!target || !item) return;
e.preventDefault();

const dropTask = api.getTask(target.id);
const mode = dropTask.type === "summary" ? "child" : "after";
const summaryId =
dropTask.type === "summary" ? dropTask.id : api.getState().tasks.getSummaryId(dropTask.id);
const dateSource = summaryId ? api.getTask(summaryId) : dropTask;

api.exec("add-task", {
task: {
text: item.text,
type: item.type || "task",
duration: item.type === "milestone" ? 0 : (item.duration ?? 1),
start: dateSource.start,
},
target: target.id,
mode,
});

backlog.value = backlog.value.filter(t => t.id !== taskId);
}

4. Attach the handlers in the markup:

<template>
<div @dragstart="onGridDragStart">
<Grid ref="tableApi" :data="backlog" :columns="backlogColumns" draggableRows />
</div>
<div @dragover="onDragOver" @drop="onDrop">
<Gantt :init="init" :tasks="data.tasks" :links="data.links" :scales="data.scales" />
</div>
</template>

Related sample: Add tasks by drag-n-drop from outside

Read-only mode​

info

In this mode you cannot create and edit tasks and links, and drag task bars.

To make the entire Gantt read-only, set the readonly property to true and define it inside the Gantt tag.

<script setup>
import { getData } from "./data";
import { Gantt } from "@svar-ui/vue-gantt";

const data = getData();

const readonly = true;
</script>

<template>
<Gantt :tasks="data.tasks" :readonly="readonly" />
</template>

Related sample: Read-only mode

Edit tasks in grid​

About the grid area and its configuration refer to Grid columns. This section describes how to apply and customize inline editors in the grid.

Applying built-in inline editors​

To apply the inline editor to column cells, set the editor parameter of the columns property to the required value ("text" | "combo" | "datepicker" | "richselect").

Example:

<script setup>
import { getData } from "../data";
import { Gantt } from "@svar-ui/vue-gantt";

const props = defineProps({ skinSettings: {} });

const data = getData();

const columns = [
{
id: "text",
header: "Task name",
width: 170,
sort: true,
editor: "text",
},
{
id: "start",
header: "Start date",
width: 120,
align: "center",
sort: true,
editor: "datepicker",
},
];
</script>

<template>
<Gantt
v-bind="props.skinSettings"
:tasks="data.tasks"
:links="data.links"
:scales="data.scales"
:columns="columns"
/>
</template>

Related sample: Grid inline editors

Customizing built-in editors​

You can apply a template and custom Vue component to the cell editor (except the "text" type editor). In this case, column "editor" should be an object with "type" and "config". "config" allows to set a custom component in the "cell" property.

Please note that for the "combo" editor, the cell component will be applied to dropdown options only, while for "datepicker" to the input field.

First, you need to prepare a custom component file. Components in editor cells have access to the data property via defineProps:

  • data - inline editors data (for example, for combo and richselect it's an item from options, for datepicker - date value)

Let's consider a custom component for values of inline editors in "start" column. The component will show formatted date and calendar icon:

DataCell component
<script setup>
const props = defineProps({ data: {} });
const options = { year: "numeric", month: "numeric", day: "numeric"};
</script>

<template>
<div v-if="data" class="container">
<span>{{ data.toLocaleString("en-US", options) }}</span>
<i class="icon wxi-calendar"></i>
</div>
</template>

<style scoped>
.container {
height: 100%;
display: flex;
align-items: center;
justify-content: space-between;
}
.icon {
display: inline-flex;
align-items: center;
font-size: 20px;
color: #b5b5b5;
}
</style>

Apply this component in "cell" property of an inline editor config:

<script setup>
import { getData } from "../data";
import { Gantt } from "@svar-ui/vue-gantt";
import DateCell from "../custom/DateCell.vue";

const data = getData();

const columns = [
{ id: "text", header: "Task name", flexgrow: 1 },
{
id: "start",
header: "Start date",
width: 120,
align: "center",
editor: {
type: "datepicker",
config: {
cell: DateCell
}
}
}
];
</script>

<template>
<Gantt
:tasks="data.tasks"
:links="data.links"
:scales="data.scales"
:columns="columns"
/>
</template>

Related sample: