Skip to content

Troubleshooting

Source code
TypeScript ts
// src/components/gantt/GanttBasic.ts
import { defineCustomElements } from '@revolist/revogrid/loader';
defineCustomElements();

import { GanttPlugin, createDefaultTaskTableColumn, defineGanttToolbar } from '@revolist/revogrid-enterprise';
import { currentTheme } from '../composables/useRandomData';
import { calendars, dependencies, ganttConfig, tasks, taskTableColumnProps, toolbarColumns } from './gantt-basic-data';
import './gantt-basic.css';

const { isDark } = currentTheme();
const columns = taskTableColumnProps.map((prop) => createDefaultTaskTableColumn(prop));

export function load(parentSelector: string) {
  const parent = document.querySelector(parentSelector);
  if (!parent) {
    return () => {};
  }

  const root = document.createElement('section');
  const toolbar = document.createElement('div');
  const grid = document.createElement('revo-grid');

  root.className = 'gantt-basic-demo';
  toolbar.className = 'gantt-basic-toolbar';
  grid.className = 'gantt-basic-grid';
  grid.theme = isDark() ? 'darkCompact' : 'compact';
  grid.hideAttribution = true;
  grid.plugins = [GanttPlugin];
  grid.gantt = ganttConfig;
  grid.ganttCalendars = calendars;
  grid.ganttDependencies = dependencies;
  grid.columns = columns;

  root.appendChild(toolbar);
  root.appendChild(grid);
  parent.appendChild(root);

  defineGanttToolbar(toolbar, {
    grid,
    columns: toolbarColumns,
    controls: {
      export: false,
      baseline: false,
    },
  });

  grid.source = tasks.map((task) => ({ ...task }));

  return () => root.remove();
}
Data ts
import type {
  CalendarEntity,
  DependencyEntity,
  GanttToolbarColumnOption,
  TaskEntity,
  TaskTableColumnProp,
} from '@revolist/revogrid-enterprise';

export const PROJECT_ID = 'project-web-redesign';
export const CALENDAR_ID = 'cal-standard';

export const ganttConfig = {
  id: PROJECT_ID,
  name: 'Website Redesign',
  version: '1',
  currency: 'USD',
  timeZone: 'UTC',
  primaryCalendarId: CALENDAR_ID,
  updatedAt: '2026-04-06T00:00:00Z',
  zoomPreset: 'week' as const,
  allowTaskCreate: true,
};

export const taskTableColumnProps: TaskTableColumnProp[] = [
  'wbs',
  'name',
  'cost',
  'startDate',
  'endDate',
  'duration',
  'workHours',
  'remainingDurationDays',
  'actualStartDate',
  'actualFinishDate',
  'effortMode',
  'effortDriven',
  'inactive',
  'priority',
  'canLevel',
  'levelingDelayDays',
  'earlyStartDate',
  'earlyFinishDate',
  'lateStartDate',
  'lateFinishDate',
  'totalSlackDays',
  'startVarianceDays',
  'finishVarianceDays',
  'durationVarianceDays',
  'progressVariancePercent',
  'taskMode',
  'scheduleOrigin',
  'constraintType',
  'constraintDate',
  'deadlineDate',
  'schedulingWarning',
  'percentDone',
  'predecessors',
  'successors',
  'status',
  'assignees',
  'resourceRole',
  'resourceCapacity',
  'resourceLoadSummary',
];

const initiallyVisibleColumnProps = new Set<TaskTableColumnProp>(['wbs', 'name']);

const allToolbarColumns = [
  { prop: 'actualFinishDate', label: 'Actual Finish' },
  { prop: 'actualStartDate', label: 'Actual Start' },
  { prop: 'assignees', label: 'Assignees' },
  { prop: 'resourceCapacity', label: 'Capacity' },
  { prop: 'canLevel', label: 'Can Level' },
  { prop: 'constraintType', label: 'Constraint' },
  { prop: 'constraintDate', label: 'Constraint Date' },
  { prop: 'cost', label: 'Cost' },
  { prop: 'deadlineDate', label: 'Deadline' },
  { prop: 'duration', label: 'Duration' },
  { prop: 'durationVarianceDays', label: 'Duration Variance' },
  { prop: 'earlyFinishDate', label: 'Early Finish' },
  { prop: 'earlyStartDate', label: 'Early Start' },
  { prop: 'effortDriven', label: 'Effort Driven' },
  { prop: 'effortMode', label: 'Effort Mode' },
  { prop: 'endDate', label: 'End Date' },
  { prop: 'finishVarianceDays', label: 'Finish Variance' },
  { prop: 'inactive', label: 'Inactive' },
  { prop: 'lateFinishDate', label: 'Late Finish' },
  { prop: 'lateStartDate', label: 'Late Start' },
  { prop: 'levelingDelayDays', label: 'Level Delay' },
  { prop: 'resourceLoadSummary', label: 'Load' },
  { prop: 'percentDone', label: '% Done' },
  { prop: 'predecessors', label: 'Predecessors' },
  { prop: 'priority', label: 'Priority' },
  { prop: 'progressVariancePercent', label: 'Progress Variance' },
  { prop: 'remainingDurationDays', label: 'Remaining' },
  { prop: 'resourceRole', label: 'Role' },
  { prop: 'scheduleOrigin', label: 'Scheduled By' },
  { prop: 'schedulingWarning', label: 'Scheduling Warning' },
  { prop: 'startDate', label: 'Start Date' },
  { prop: 'startVarianceDays', label: 'Start Variance' },
  { prop: 'status', label: 'Status' },
  { prop: 'successors', label: 'Successors' },
  { prop: 'name', label: 'Task' },
  { prop: 'taskMode', label: 'Task Mode' },
  { prop: 'totalSlackDays', label: 'Total Slack' },
  { prop: 'wbs', label: 'WBS' },
  { prop: 'workHours', label: 'Work Hours' },
] satisfies Array<Omit<GanttToolbarColumnOption, 'visible'>>;

export const toolbarColumns: GanttToolbarColumnOption[] = [...allToolbarColumns]
  .sort((a, b) => a.label.localeCompare(b.label, undefined, { sensitivity: 'base' }))
  .map((column) => ({
    ...column,
    visible: initiallyVisibleColumnProps.has(column.prop as TaskTableColumnProp),
  }));

export const calendars: CalendarEntity[] = [
  {
    id: CALENDAR_ID,
    name: 'Standard',
    timeZone: 'UTC',
    workingDays: [1, 2, 3, 4, 5],
    holidays: [],
    hoursPerDay: 8,
  },
];

export const tasks: TaskEntity[] = [
  {
    id: 't1', projectId: PROJECT_ID, parentId: null,
    wbsCode: '1', name: 'Discovery', type: 'summary',
    status: 'done',
    startDate: '2026-04-06', endDate: '2026-04-17', durationDays: 10,
    progressPercent: 100, calendarId: CALENDAR_ID, isCritical: false, tags: [],
  },
  {
    id: 't2', projectId: PROJECT_ID, parentId: 't1',
    wbsCode: '1.1', name: 'Stakeholder Interviews', type: 'task',
    status: 'done',
    startDate: '2026-04-06', endDate: '2026-04-08', durationDays: 3,
    progressPercent: 100, calendarId: CALENDAR_ID, isCritical: false, tags: [],
  },
  {
    id: 't3', projectId: PROJECT_ID, parentId: 't1',
    wbsCode: '1.2', name: 'Analytics Review', type: 'task',
    status: 'done',
    startDate: '2026-04-07', endDate: '2026-04-10', durationDays: 4,
    progressPercent: 100, calendarId: CALENDAR_ID, isCritical: false, tags: [],
  },
  {
    id: 't4', projectId: PROJECT_ID, parentId: 't1',
    wbsCode: '1.3', name: 'Content Inventory', type: 'task',
    status: 'done',
    startDate: '2026-04-09', endDate: '2026-04-14', durationDays: 4,
    progressPercent: 100, calendarId: CALENDAR_ID, isCritical: false, tags: [],
  },
  {
    id: 't5', projectId: PROJECT_ID, parentId: 't1',
    wbsCode: '1.4', name: 'Requirements Workshop', type: 'task',
    status: 'done',
    startDate: '2026-04-13', endDate: '2026-04-16', durationDays: 4,
    progressPercent: 100, calendarId: CALENDAR_ID, isCritical: false, tags: [],
  },
  {
    id: 't6', projectId: PROJECT_ID, parentId: 't1',
    wbsCode: '1.5', name: 'Discovery Sign-off', type: 'milestone',
    status: 'done',
    startDate: '2026-04-17', endDate: '2026-04-17', durationDays: 0,
    progressPercent: 100, calendarId: CALENDAR_ID, isCritical: true, tags: ['milestone'],
  },
  {
    id: 't7', projectId: PROJECT_ID, parentId: null,
    wbsCode: '2', name: 'Design', type: 'summary',
    status: 'in-progress',
    startDate: '2026-04-20', endDate: '2026-05-08', durationDays: 15,
    progressPercent: 55, calendarId: CALENDAR_ID, isCritical: true, tags: [],
  },
  {
    id: 't8', projectId: PROJECT_ID, parentId: 't7',
    wbsCode: '2.1', name: 'Information Architecture', type: 'task',
    status: 'done',
    startDate: '2026-04-20', endDate: '2026-04-23', durationDays: 4,
    progressPercent: 100, calendarId: CALENDAR_ID, isCritical: true, tags: [],
  },
  {
    id: 't9', projectId: PROJECT_ID, parentId: 't7',
    wbsCode: '2.2', name: 'Wireframes', type: 'task',
    status: 'done',
    startDate: '2026-04-24', endDate: '2026-04-29', durationDays: 4,
    progressPercent: 100, calendarId: CALENDAR_ID, isCritical: true, tags: [],
  },
  {
    id: 't10', projectId: PROJECT_ID, parentId: 't7',
    wbsCode: '2.3', name: 'Design System Updates', type: 'task',
    status: 'in-progress',
    startDate: '2026-04-27', endDate: '2026-05-01', durationDays: 5,
    progressPercent: 70, calendarId: CALENDAR_ID, isCritical: false, tags: [],
  },
  {
    id: 't11', projectId: PROJECT_ID, parentId: 't7',
    wbsCode: '2.4', name: 'Visual Design', type: 'task',
    status: 'in-progress',
    startDate: '2026-04-30', endDate: '2026-05-07', durationDays: 6,
    progressPercent: 45, calendarId: CALENDAR_ID, isCritical: true, tags: [],
  },
  {
    id: 't12', projectId: PROJECT_ID, parentId: 't7',
    wbsCode: '2.5', name: 'Prototype Review', type: 'task',
    status: 'not-started',
    startDate: '2026-05-05', endDate: '2026-05-07', durationDays: 3,
    progressPercent: 0, calendarId: CALENDAR_ID, isCritical: false, tags: [],
  },
  {
    id: 't13', projectId: PROJECT_ID, parentId: 't7',
    wbsCode: '2.6', name: 'Design Approval', type: 'milestone',
    status: 'not-started',
    startDate: '2026-05-08', endDate: '2026-05-08', durationDays: 0,
    progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: ['milestone'],
  },
  {
    id: 't14', projectId: PROJECT_ID, parentId: null,
    wbsCode: '3', name: 'Development', type: 'summary',
    status: 'not-started',
    startDate: '2026-05-11', endDate: '2026-06-05', durationDays: 20,
    progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: [],
  },
  {
    id: 't15', projectId: PROJECT_ID, parentId: 't14',
    wbsCode: '3.1', name: 'Frontend Shell', type: 'task',
    status: 'not-started',
    startDate: '2026-05-11', endDate: '2026-05-15', durationDays: 5,
    progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: [],
  },
  {
    id: 't16', projectId: PROJECT_ID, parentId: 't14',
    wbsCode: '3.2', name: 'CMS Integration', type: 'task',
    status: 'not-started',
    startDate: '2026-05-11', endDate: '2026-05-20', durationDays: 8,
    progressPercent: 0, calendarId: CALENDAR_ID, isCritical: false, tags: [],
  },
  {
    id: 't17', projectId: PROJECT_ID, parentId: 't14',
    wbsCode: '3.3', name: 'Reusable Page Sections', type: 'task',
    status: 'not-started',
    startDate: '2026-05-18', endDate: '2026-05-27', durationDays: 8,
    progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: [],
  },
  {
    id: 't18', projectId: PROJECT_ID, parentId: 't14',
    wbsCode: '3.4', name: 'Search Experience', type: 'task',
    status: 'not-started',
    startDate: '2026-05-19', endDate: '2026-05-26', durationDays: 6,
    progressPercent: 0, calendarId: CALENDAR_ID, isCritical: false, tags: [],
  },
  {
    id: 't19', projectId: PROJECT_ID, parentId: 't14',
    wbsCode: '3.5', name: 'Analytics Events', type: 'task',
    status: 'not-started',
    startDate: '2026-05-25', endDate: '2026-05-29', durationDays: 5,
    progressPercent: 0, calendarId: CALENDAR_ID, isCritical: false, tags: [],
  },
  {
    id: 't20', projectId: PROJECT_ID, parentId: 't14',
    wbsCode: '3.6', name: 'Accessibility Pass', type: 'task',
    status: 'not-started',
    startDate: '2026-05-28', endDate: '2026-06-02', durationDays: 4,
    progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: [],
  },
  {
    id: 't21', projectId: PROJECT_ID, parentId: 't14',
    wbsCode: '3.7', name: 'Performance Tuning', type: 'task',
    status: 'not-started',
    startDate: '2026-06-01', endDate: '2026-06-04', durationDays: 4,
    progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: [],
  },
  {
    id: 't22', projectId: PROJECT_ID, parentId: 't14',
    wbsCode: '3.8', name: 'Feature Complete', type: 'milestone',
    status: 'not-started',
    startDate: '2026-06-05', endDate: '2026-06-05', durationDays: 0,
    progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: ['milestone'],
  },
  {
    id: 't23', projectId: PROJECT_ID, parentId: null,
    wbsCode: '4', name: 'QA and Release Prep', type: 'summary',
    status: 'not-started',
    startDate: '2026-06-08', endDate: '2026-06-18', durationDays: 9,
    progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: [],
  },
  {
    id: 't24', projectId: PROJECT_ID, parentId: 't23',
    wbsCode: '4.1', name: 'Test Plan', type: 'task',
    status: 'not-started',
    startDate: '2026-06-08', endDate: '2026-06-10', durationDays: 3,
    progressPercent: 0, calendarId: CALENDAR_ID, isCritical: false, tags: [],
  },
  {
    id: 't25', projectId: PROJECT_ID, parentId: 't23',
    wbsCode: '4.2', name: 'Cross-browser QA', type: 'task',
    status: 'not-started',
    startDate: '2026-06-10', endDate: '2026-06-15', durationDays: 4,
    progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: [],
  },
  {
    id: 't26', projectId: PROJECT_ID, parentId: 't23',
    wbsCode: '4.3', name: 'Content QA', type: 'task',
    status: 'not-started',
    startDate: '2026-06-11', endDate: '2026-06-16', durationDays: 4,
    progressPercent: 0, calendarId: CALENDAR_ID, isCritical: false, tags: [],
  },
  {
    id: 't27', projectId: PROJECT_ID, parentId: 't23',
    wbsCode: '4.4', name: 'Release Candidate', type: 'milestone',
    status: 'not-started',
    startDate: '2026-06-18', endDate: '2026-06-18', durationDays: 0,
    progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: ['milestone'],
  },
  {
    id: 't28', projectId: PROJECT_ID, parentId: null,
    wbsCode: '5', name: 'Launch', type: 'task',
    status: 'not-started',
    startDate: '2026-06-19', endDate: '2026-06-23', durationDays: 3,
    progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: [],
  },
  {
    id: 't29', projectId: PROJECT_ID, parentId: null,
    wbsCode: '6', name: 'Post-launch Review', type: 'milestone',
    status: 'not-started',
    startDate: '2026-06-26', endDate: '2026-06-26', durationDays: 0,
    progressPercent: 0, calendarId: CALENDAR_ID, isCritical: false, tags: ['milestone'],
  },
];

export const dependencies: DependencyEntity[] = [
  { id: 'd1', predecessorTaskId: 't2', successorTaskId: 't5', type: 'finish-to-start', lagDays: 0 },
  { id: 'd2', predecessorTaskId: 't3', successorTaskId: 't5', type: 'finish-to-start', lagDays: 0 },
  { id: 'd3', predecessorTaskId: 't4', successorTaskId: 't6', type: 'finish-to-start', lagDays: 0 },
  { id: 'd4', predecessorTaskId: 't5', successorTaskId: 't6', type: 'finish-to-start', lagDays: 0 },
  { id: 'd5', predecessorTaskId: 't6', successorTaskId: 't8', type: 'finish-to-start', lagDays: 1 },
  { id: 'd6', predecessorTaskId: 't8', successorTaskId: 't9', type: 'finish-to-start', lagDays: 0 },
  { id: 'd7', predecessorTaskId: 't9', successorTaskId: 't11', type: 'finish-to-start', lagDays: 0 },
  { id: 'd8', predecessorTaskId: 't10', successorTaskId: 't12', type: 'finish-to-start', lagDays: 0 },
  { id: 'd9', predecessorTaskId: 't11', successorTaskId: 't13', type: 'finish-to-start', lagDays: 0 },
  { id: 'd10', predecessorTaskId: 't12', successorTaskId: 't13', type: 'finish-to-start', lagDays: 0 },
  { id: 'd11', predecessorTaskId: 't13', successorTaskId: 't15', type: 'finish-to-start', lagDays: 1 },
  { id: 'd12', predecessorTaskId: 't15', successorTaskId: 't17', type: 'finish-to-start', lagDays: 0 },
  { id: 'd13', predecessorTaskId: 't16', successorTaskId: 't18', type: 'finish-to-start', lagDays: 0 },
  { id: 'd14', predecessorTaskId: 't17', successorTaskId: 't20', type: 'finish-to-start', lagDays: 0 },
  { id: 'd15', predecessorTaskId: 't18', successorTaskId: 't19', type: 'finish-to-start', lagDays: 0 },
  { id: 'd16', predecessorTaskId: 't19', successorTaskId: 't21', type: 'finish-to-start', lagDays: 0 },
  { id: 'd17', predecessorTaskId: 't20', successorTaskId: 't21', type: 'finish-to-start', lagDays: 0 },
  { id: 'd18', predecessorTaskId: 't21', successorTaskId: 't22', type: 'finish-to-start', lagDays: 0 },
  { id: 'd19', predecessorTaskId: 't22', successorTaskId: 't24', type: 'finish-to-start', lagDays: 1 },
  { id: 'd20', predecessorTaskId: 't24', successorTaskId: 't25', type: 'finish-to-start', lagDays: 0 },
  { id: 'd21', predecessorTaskId: 't24', successorTaskId: 't26', type: 'finish-to-start', lagDays: 0 },
  { id: 'd22', predecessorTaskId: 't25', successorTaskId: 't27', type: 'finish-to-start', lagDays: 0 },
  { id: 'd23', predecessorTaskId: 't26', successorTaskId: 't27', type: 'finish-to-start', lagDays: 0 },
  { id: 'd24', predecessorTaskId: 't27', successorTaskId: 't28', type: 'finish-to-start', lagDays: 0 },
  { id: 'd25', predecessorTaskId: 't28', successorTaskId: 't29', type: 'finish-to-start', lagDays: 2 },
];
Vue vue
<template>
  <section class="gantt-basic-demo">
    <div ref="toolbarRef" class="gantt-basic-toolbar"></div>
    <RevoGrid
      ref="gridRef"
      class="gantt-basic-grid"
      hide-attribution
      :theme="isDark ? 'darkCompact' : 'compact'"
      :plugins="plugins"
      :source="tasks"
      :columns="columns"
      :gantt.prop="ganttConfig"
      :gantt-dependencies.prop="dependencies"
      :gantt-calendars.prop="calendars"
    />
  </section>
</template>

<script setup lang="ts">
import { nextTick, onBeforeUnmount, onMounted, ref } from 'vue';
import RevoGrid from '@revolist/vue3-datagrid';
import { GanttPlugin, createDefaultTaskTableColumn, defineGanttToolbar } from '@revolist/revogrid-enterprise';
import { currentThemeVue } from '../composables/useRandomData';
import { calendars as basicCalendars, dependencies as basicDependencies, ganttConfig as basicGanttConfig, tasks as basicTasks, taskTableColumnProps, toolbarColumns } from './gantt-basic-data';
import './gantt-basic.css';

const { isDark } = currentThemeVue();

const plugins = ref([GanttPlugin]);
const ganttConfig = ref(basicGanttConfig);
const calendars = ref(basicCalendars);
const tasks = ref(basicTasks.map((task) => ({ ...task })));
const dependencies = ref(basicDependencies);

const columns = ref(taskTableColumnProps.map((prop) => createDefaultTaskTableColumn(prop)));

const gridRef = ref<InstanceType<typeof RevoGrid> | HTMLRevoGridElement | null>(null);
const toolbarRef = ref<HTMLElement | null>(null);
let toolbarMounted = false;
let toolbarFrame = 0;

function getGridEl(): HTMLRevoGridElement | null {
  const refValue = gridRef.value as (InstanceType<typeof RevoGrid> & { $el?: HTMLRevoGridElement }) | HTMLRevoGridElement | null;
  const candidate = (refValue && '$el' in refValue ? refValue.$el : refValue) ?? null;
  return candidate instanceof HTMLElement && candidate.tagName.toLowerCase() === 'revo-grid'
    ? candidate as HTMLRevoGridElement
    : null;
}

function mountToolbar() {
  if (toolbarMounted) {
    return;
  }

  const grid = getGridEl();
  if (!toolbarRef.value || !grid) {
    toolbarFrame = requestAnimationFrame(mountToolbar);
    return;
  }

  toolbarMounted = true;
  defineGanttToolbar(toolbarRef.value, {
    grid,
    columns: toolbarColumns,
    controls: {
      export: false,
      baseline: false,
    },
  });
}

onMounted(async () => {
  await nextTick();
  mountToolbar();
});

onBeforeUnmount(() => {
  if (toolbarFrame) {
    cancelAnimationFrame(toolbarFrame);
  }
  if (toolbarRef.value) {
    toolbarRef.value.textContent = '';
  }
});
</script>
React tsx
// src/components/gantt/GanttBasic.tsx
import React, { useEffect, useMemo, useRef } from 'react';
import { RevoGrid } from '@revolist/react-datagrid';
import { GanttPlugin, createDefaultTaskTableColumn, defineGanttToolbar } from '@revolist/revogrid-enterprise';
import { currentTheme } from '../composables/useRandomData';
import { calendars, dependencies, ganttConfig, tasks, taskTableColumnProps, toolbarColumns } from './gantt-basic-data';
import './gantt-basic.css';

const { isDark } = currentTheme();

function GanttBasic() {
  const gridRef = useRef<HTMLRevoGridElement>(null);
  const toolbarRef = useRef<HTMLDivElement>(null);
  const project = useMemo(() => ganttConfig, []);
  const source = useMemo(() => tasks.map((task) => ({ ...task })), []);

  const columns = useMemo(() => taskTableColumnProps.map((prop) => createDefaultTaskTableColumn(prop)), []);

  useEffect(() => {
    const toolbar = toolbarRef.current;
    const grid = gridRef.current;
    if (!toolbar || !grid) {
      return undefined;
    }

    defineGanttToolbar(toolbar, {
      grid,
      columns: toolbarColumns,
      controls: {
        export: false,
        baseline: false,
      },
    });

    return () => {
      toolbar.textContent = '';
    };
  }, [columns]);

  return (
    <section className="gantt-basic-demo">
      <div ref={toolbarRef} className="gantt-basic-toolbar" />
      <RevoGrid
        ref={gridRef}
        className="gantt-basic-grid"
        theme={isDark() ? 'darkCompact' : 'compact'}
        hideAttribution
        plugins={[GanttPlugin]}
        source={source}
        columns={columns}
        gantt={project}
        ganttDependencies={dependencies}
        ganttCalendars={calendars}
      />
    </section>
  );
}

export default GanttBasic;
Angular ts
// src/components/gantt/GanttBasicAngular.ts
import { AfterViewInit, Component, ElementRef, NO_ERRORS_SCHEMA, ViewChild, ViewEncapsulation } from '@angular/core';
import { RevoGrid } from '@revolist/angular-datagrid';
import { GanttPlugin, createDefaultTaskTableColumn, defineGanttToolbar } from '@revolist/revogrid-enterprise';
import { currentTheme } from '../composables/useRandomData';
import { calendars as basicCalendars, dependencies as basicDependencies, ganttConfig as basicGanttConfig, tasks as basicTasks, taskTableColumnProps, toolbarColumns } from './gantt-basic-data';

@Component({
  selector: 'gantt-basic-grid',
  standalone: true,
  // Allows Angular demos to bind RevoGrid plugin props that are not wrapper inputs.
  schemas: [NO_ERRORS_SCHEMA],
  imports: [RevoGrid],
  template: `
    <section class="gantt-basic-demo">
      <div #toolbar class="gantt-basic-toolbar"></div>
      <revo-grid
        #grid
        class="gantt-basic-grid"
        [theme]="theme"
        [hideAttribution]="true"
        [plugins]="plugins"
        [source]="tasks"
        [columns]="columns"
        [gantt]="ganttConfig"
        [ganttDependencies]="dependencies"
        [ganttCalendars]="calendars"
      ></revo-grid>
    </section>
  `,
  styleUrls: ['./gantt-basic.css'],
  encapsulation: ViewEncapsulation.None,
})
export class GanttBasicGridComponent implements AfterViewInit {
  @ViewChild('grid', { read: ElementRef }) gridRef!: ElementRef<HTMLRevoGridElement>;
  @ViewChild('toolbar', { read: ElementRef }) toolbarRef!: ElementRef<HTMLElement>;

  theme = currentTheme().isDark() ? 'darkCompact' : 'compact';
  plugins = [GanttPlugin];

  ganttConfig = basicGanttConfig;
  calendars = basicCalendars;
  tasks = basicTasks.map((task) => ({ ...task }));
  dependencies = basicDependencies;

  columns = taskTableColumnProps.map((prop) => createDefaultTaskTableColumn(prop));

  ngAfterViewInit(): void {
    defineGanttToolbar(this.toolbarRef.nativeElement, {
      grid: this.gridRef.nativeElement,
      columns: toolbarColumns,
      controls: {
        export: false,
        baseline: false,
      },
    });
  }
}

Common checks:

  • Missing ganttCalendars or mismatched calendarId.
  • Duplicate IDs in tasks/dependencies/resources/assignments.
  • Dependency points to missing task ID.
  • Invalid task date ranges or malformed constraints.
  • No visible timeline because viewport/zoom span does not include task dates.

Validation and diagnostics are produced by:

  • engine/scheduler-validation.ts
  • engine/scheduler-types.ts