Skip to content

Dependencies

Source code
TypeScript ts
import { GANTT_DEPENDENCIES_ADVANCED_DEMO } from './gantt-advanced-data';
import { loadAdvancedGanttDemo } from './GanttAdvancedVanillaDemo';

export function load(parentSelector: string) {
  return loadAdvancedGanttDemo(parentSelector, GANTT_DEPENDENCIES_ADVANCED_DEMO);
}
Vue vue
<template>
  <GanttAdvancedDemo :demo="GANTT_DEPENDENCIES_ADVANCED_DEMO" />
</template>

<script setup lang="ts">
import GanttAdvancedDemo from './GanttAdvancedDemo.vue';
import { GANTT_DEPENDENCIES_ADVANCED_DEMO } from './gantt-advanced-data';
</script>
React tsx
import React from 'react';
import GanttAdvancedDemo from './GanttAdvancedReactDemo';
import { GANTT_DEPENDENCIES_ADVANCED_DEMO } from './gantt-advanced-data';

export default function GanttDependenciesAdvanced() {
  return <GanttAdvancedDemo demo={GANTT_DEPENDENCIES_ADVANCED_DEMO} />;
}
Angular ts
import { Component, NO_ERRORS_SCHEMA, ViewEncapsulation } from '@angular/core';
import { RevoGrid } from '@revolist/angular-datagrid';
import { GanttAdvancedAngularBase } from './GanttAdvancedAngularBase';
import { GANTT_DEPENDENCIES_ADVANCED_DEMO } from './gantt-advanced-data';

@Component({
  selector: 'gantt-dependencies-advanced-grid',
  standalone: true,
  // Allows Angular demos to bind RevoGrid plugin props that are not wrapper inputs.
  schemas: [NO_ERRORS_SCHEMA],
  imports: [RevoGrid],
  template: `<revo-grid style="min-height: 560px" [theme]="theme" [hideAttribution]="true" [plugins]="plugins" [source]="tasks" [columns]="columns" [gantt]="ganttConfig" [ganttDependencies]="dependencies" [ganttCalendars]="calendars" [ganttResources]="resources" [ganttAssignments]="assignments"></revo-grid>`,
  encapsulation: ViewEncapsulation.None,
})
export class GanttDependenciesAdvancedGridComponent extends GanttAdvancedAngularBase {
  protected readonly demo = GANTT_DEPENDENCIES_ADVANCED_DEMO;
}

Dependencies constrain automatic successors using the relationship type and optional lag:

| Type | MSP token | Constraint | |---|---|---| | finish-to-start | FS | Successor starts after predecessor finishes. | | start-to-start | SS | Successor starts no earlier than predecessor starts. | | finish-to-finish | FF | Successor finishes no earlier than predecessor finishes. | | start-to-finish | SF | Successor finishes no earlier than predecessor starts. |

Use lagDays for lag or lead:

grid.ganttDependencies = [
{
id: 'build-test',
predecessorTaskId: 'build',
successorTaskId: 'test',
type: 'finish-to-start',
lagDays: -2,
},
];

Positive lagDays delays the successor. Negative lagDays is lead time and allows overlap, matching Microsoft Project's negative lead syntax.

lagCalendar in scheduling config controls whether lag is interpreted as calendar days or working days.

Inline predecessor/successor cells accept MSP-style tokens:

1FS
2SS+3
3FF-1d
task-4SF-2

Blank or invalid lag normalizes to 0. The optional d suffix is accepted. Whitespace around tokens is ignored.

Important dependency behavior:

  • Circular dependency chains are invalid schedule data. RevoGrid reports them as dependency-cycle issues with the involved taskIds and dependencyIds.
  • New dependency edits that would create a cycle are rejected before they change the Gantt store.
  • Task row drops that would make dependency partners parent/child through the outline are rejected before the drop is committed.
  • Imported projects that already contain a cycle still render, but automatic dependency propagation and drag/resize dependency clamping are not applied while the active dependency graph is cyclic.
  • Missing predecessor/successor references produce issues.
  • Dependency links are rendered in the overlay layer and can be created/edited interactively.

This matches the Microsoft Project scheduling model: a loop such as Setup load balancer -> Configure firewall -> Setup load balancer cannot produce a valid schedule. Remove or change one of the invalid links, then rerun scheduling.

When building diagnostics UI, inspect the scheduling result issues:

const cycle = schedulerResult.issues.find((issue) => issue.code === 'dependency-cycle');
if (cycle) {
console.warn('Dependency cycle', {
taskIds: cycle.taskIds,
dependencyIds: cycle.dependencyIds,
});
}

An automatic successor cannot silently move before its predecessor allows:

grid.source = [
{
id: 'design',
name: 'Design',
startDate: '2026-04-01',
duration: 3,
taskMode: 'auto',
},
{
id: 'build',
name: 'Build',
startDate: '2026-04-01',
duration: 2,
taskMode: 'auto',
},
];
grid.ganttDependencies = [{
id: 'design-build',
predecessorTaskId: 'design',
successorTaskId: 'build',
type: 'finish-to-start',
lagDays: 0,
}];

Expected result: design ends on 2026-04-03, so build is scheduled no earlier than 2026-04-04. If the user drags build left, the effective bar snaps back to the dependency-valid date.

Manual tasks preserve authored dates, but dependency violations remain visible:

grid.source = [
{ id: 'design', startDate: '2026-04-01', duration: 3 },
{
id: 'review',
name: 'Manual Review',
startDate: '2026-04-02',
duration: 1,
taskMode: 'manual',
},
];
grid.ganttDependencies = [{
id: 'design-review',
predecessorTaskId: 'design',
successorTaskId: 'review',
type: 'finish-to-start',
lagDays: 0,
}];

Expected result: review stays on 2026-04-02 and receives a manual-dependency-violation warning because the dependency requires 2026-04-04.

See the Advanced dependencies demo for a runnable project containing FS, SS, FF, and SF links with lag and lead.

Implementation sources:

  • packages/enterprise/plugins/gantt/engine/dependency-graph.ts
  • packages/enterprise/plugins/gantt/engine/scheduler-engine/validation.ts
  • packages/enterprise/plugins/gantt/features/dependencies/