Skip to main content

Assign resources

PRO

The functionality is available in PRO Edition only

Resource management lets end users see who is responsible for each task directly in the grid and assign or unassign team members to distribute work. You can also query assignments at runtime and serialize resource and assignment data for backend integration.

Assignment rules​

These rules apply to all assignment operations. Gantt silently ignores any operation that violates them.

  • Only leaf resources (those with no children) support assignment. You can't assign parent or group resources directly.
  • You can only assign resources to leaf tasks. Summary tasks don't support assignments.
  • You can't assign the same resource to the same task twice.
  • Deleting a task removes all its assignments automatically.
  • When you change resource via update-assignment, make sure the new resource has no existing assignment on that task.

Assign resources​

Resources represent people or other entities you assign to tasks. You can configure them through two separate arrays: resources and assignments.

Define resources​

To define your resources, pass an array of resource objects to the resources property. Use optional parent field to build a hierarchy:

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

const resources = [
{ id: "team1", name: "Frontend Team" },
{ id: "r1", name: "Alice", role: "Developer", color: "#4CAF50", parent: "team1" },
{ id: "r2", name: "Bob", role: "Designer", color: "#2196F3", parent: "team1" },
];
</script>

<template>
<Gantt :tasks="..." :resources="resources" />
</template>

Pass the assignments array to define which resources connect to which tasks. Each assignment links one resource to one task:

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

const assignments = [
{ id: 1, task: 1, resource: "r1" }, // Alice at 100%
{ id: 2, task: 1, resource: "r2", units: 50 }, // Bob at 50%
{ id: 3, task: 2, resource: "r1" },
];
</script>

<template>
<Gantt :tasks="..." :resources="resources" :assignments="assignments" />
</template>

The units field sets the allocation percentage (0–100). It defaults to 100 when omitted.

See Assignment rules for constraints on which resources and tasks support assignments.

Add and remove assignments at runtime​

Call api.exec() with the relevant action to manage assignments after initialization:

// Assign a resource to a task
api.exec("add-assignment", {
assignment: { task: 1, resource: "r1", units: 100 },
});

// Update the allocation of an existing assignment
api.exec("update-assignment", {
id: 1,
assignment: { units: 50 },
});

// Remove an assignment by its id
api.exec("delete-assignment", { id: 1 });

Assign resources by drag and drop​

You can let users drag a resource onto a task to assign it, either from outside (e.g., a resource grid) or from the resource load view. Both rely on:

  • The draggableRows prop (boolean | (row) => boolean), available on Grid and ResourceLoad, to enable native HTML5 drag-and-drop on the resource rows.
  • The exported locateTask helper, used during dragover/drop to find the task under the pointer:
locateTask(ev: MouseEvent | DragEvent, api?: IApi): { id: TID, node: HTMLElement } | null

It returns the target task id and its DOM node (grid row or chart bar), or null when the pointer isn't over a task. Check task.type !== "summary" before calling add-assignment, since summaries can't be assigned (see Assignment rules).

Drag from a resource grid​

Set draggableRows on a Grid that lists your leaf resources, 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 on dataTransfer under a custom MIME type and its name as plain text:

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

const MIME = "application/x-my-resource";
const api = ref(null);
const tableApi = ref(null);

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.name);
e.dataTransfer.effectAllowed = "copy";
}

2. Track the drop target. On dragover, call locateTask to find the task under the pointer, and allow the drop only over non-summary tasks:

function onDragOver(e) {
if (!e.dataTransfer.types.includes(MIME)) return;
const target = locateTask(e, api.value);
if (!target || api.value.getTask(target.id).type === "summary") return;
e.preventDefault();
e.dataTransfer.dropEffect = "copy";
}

3. Assign on drop. Read the resource id back from dataTransfer, locate the task again, and call add-assignment:

function onDrop(e) {
if (!e.dataTransfer.types.includes(MIME) || !api.value) return;
const resourceId = JSON.parse(e.dataTransfer.getData(MIME));
const target = locateTask(e, api.value);
if (!target || api.value.getTask(target.id).type === "summary") return;
e.preventDefault();

api.value.exec("add-assignment", {
assignment: { task: target.id, resource: resourceId },
});
}

4. Attach the handlers in the markup.

<template>
<div @dragstart="onGridDragStart">
<Grid ref="tableApi" :data="leafResources" :columns="resourceColumns" draggableRows />
</div>
<div @dragover="onDragOver" @drop="onDrop">
<Gantt ref="api" :tasks="tasks" :links="links" :scales="scales" :resources="resources" :assignments="assignments" />
</div>
</template>

Related sample: Drag resources onto tasks

Drag from the resource load view​

ResourceLoad accepts the same draggableRows prop. Pass (row) => boolean function to exclude group rows (those with a data array) from dragging. Reuse onDragOver from Drag from a resource grid unchanged, it only depends on api and the shared MIME type:

<script setup>
import { ref } from "vue";
import { locateID } from "@svar-ui/lib-dom";
import { Gantt, ResourceLoad, locateTask } from "@svar/vue-gantt";

const MIME = "application/x-my-resource";
const api = ref(null);

function onLoadDragStart(e) {
const id = locateID(e);
if (id == null) return;
e.dataTransfer.setData(MIME, JSON.stringify(id));
e.dataTransfer.effectAllowed = "copy";
}

function onDrop(e) {
if (!e.dataTransfer.types.includes(MIME) || !api.value) return;
const resourceId = JSON.parse(e.dataTransfer.getData(MIME));
const target = locateTask(e, api.value);
const resource = api.value.getResource(resourceId);
if (!target || api.value.getTask(target.id).type === "summary" || !resource) return;
e.preventDefault();

api.value.exec("add-assignment", {
assignment: { task: target.id, resource: resourceId },
});
}
</script>

<template>
<div @dragover="onDragOver" @drop="onDrop">
<Gantt ref="api" :tasks="tasks" :links="links" :scales="scales" :resources="resources" :assignments="assignments" />
</div>
<div @dragstart="onLoadDragStart">
<ResourceLoad :api="api" :draggableRows="row => !row.data?.length" />
</div>
</template>

Related sample: Drag from resource load

Query assignments​

Call api.getTaskResources(id) to get all resources assigned to a task:

const resources = api.getTaskResources(1);
// [{ id: "r1", name: "Alice", ... }, { id: "r2", name: "Bob", ... }]

api.getResourceTasks(id) works in reverse, it returns all tasks for a given resource:

const tasks = api.getResourceTasks("r1");
// [{ id: 1, text: "Design mockups", ... }, ...] or [] if no assignments exist

Lazy loading assignments​

When tasks use lazy: true (see Dynamic data loading), the assignments that belong to the child tasks must be delivered together with those tasks. The handler for request-data should fetch them and forward them through provide-data:

api.on("request-data", ev => {
restProvider
.getData(ev.id, { assignments: true })
.then(({ tasks, links, assignments }) => {
api.exec("provide-data", {
id: ev.id,
data: { tasks, links, assignments },
});
});
});

Without this, child-task assignments are never loaded — the resource column for the opened branch stays empty and resource-load won't include those tasks.

Serialize resource data​

To read the current resources or assignments out of Gantt as plain arrays (for saving to a server or local state), call api.serialize() with data parameter:

const resources = api.serialize({ data: "resources" });
const assignments = api.serialize({ data: "assignments" });

Display resources in the grid​

When you pass the resources array to <Gantt>, the resource column is added to the grid automatically. It shows each task's assigned members as avatar badges, but is read-only by default.

To make the column editable with an inline multiselect picker, get the default columns via getDefaultColumns and attach the multiselect editor to the resources column:

<script setup>
import { Gantt, getDefaultColumns } from "@svar/vue-gantt";

const columns = getDefaultColumns({ resources: true });
columns.find(c => c.id === "resources").editor = "multiselect";
</script>

<template>
<Gantt :tasks="tasks" :resources="resources" :assignments="assignments" :columns="columns" />
</template>

Edit assignments in the Editor​

The Editor component adds the Resources tab automatically when resources are passed to <Gantt>. No extra configuration is needed, just place <Editor :api="api" /> next to the Gantt:

<script setup>
import { Gantt, Editor, getDefaultColumns } from "@svar/vue-gantt";
import { ref } from "vue";

const api = ref(null);
</script>

<template>
<Gantt
ref="api"
:tasks="tasks"
:links="links"
:scales="scales"
:resources="resources"
:assignments="assignments"
:columns="getDefaultColumns({ resources: true })"
/>
<Editor :api="api" />
</template>

The Resources tab lets users assign resources, adjust allocation (units), and remove assignments. It is hidden automatically for summary tasks.

Resource load​

The ResourceLoad component visualizes how much work is allocated per resource per day. See Resource load for the full guide.

Sort resources​

To sort the resource grid programmatically, call api.exec() with the sort-resources action:

api.exec("sort-resources", { key: "name", order: "asc" });

For multi-level sorting, call the action again with add: true:

api.exec("sort-resources", { key: "role", order: "asc", add: true });

Group by resource​

You can reorganize the task grid by assigned resource or any other task field. See Grouping tasks for the full guide.


Related samples:

Related articles: