Backend API
<div id="demo-container">
<div class="options">
<div class="caption">Options</div>
<div class="option">
<dx-check-box
text="Auto Update Parent Tasks"
[(value)]="autoUpdateParentTasks"
></dx-check-box>
</div>
<div class="option">
<dx-check-box
text="Enable Dependency Validation"
[(value)]="validateDependencies"
></dx-check-box>
</div>
<div class="option">
<dx-check-box
text="Enable Predecessor Gap"
[(value)]="enablePredecessorGap"
></dx-check-box>
</div>
</div>
<div class="widget-container">
<dx-gantt taskListWidth="500" height="700" taskTitlePosition="none">
<dxo-gantt-validation
[autoUpdateParentTasks]="autoUpdateParentTasks"
[validateDependencies]="validateDependencies"
[enablePredecessorGap]="enablePredecessorGap"
></dxo-gantt-validation>
<dxo-gantt-tasks [dataSource]="tasks"></dxo-gantt-tasks>
<dxo-gantt-dependencies
[dataSource]="dependencies"
></dxo-gantt-dependencies>
<dxi-gantt-column
dataField="title"
caption="Task"
[width]="300"
></dxi-gantt-column>
<dxi-gantt-column
dataField="start"
caption="Start Date"
dataType="date"
></dxi-gantt-column>
<dxi-gantt-column
dataField="end"
caption="End Date"
dataType="date"
></dxi-gantt-column>
<dxo-gantt-editing [enabled]="true"></dxo-gantt-editing>
</dx-gantt>
</div>
</div>
import { bootstrapApplication } from '@angular/platform-browser';
import { Component, enableProdMode, provideZoneChangeDetection } from '@angular/core';
import { DxGanttModule, DxCheckBoxModule } from 'devextreme-angular';
import { Service, Task, Dependency } from './app.service';
if (!/localhost/.test(document.location.host)) {
enableProdMode();
}
@Component({
selector: 'demo-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
providers: [Service],
preserveWhitespaces: true,
imports: [
DxGanttModule,
DxCheckBoxModule,
],
})
export class AppComponent {
tasks: Task[];
dependencies: Dependency[];
autoUpdateParentTasks: boolean;
validateDependencies: boolean;
enablePredecessorGap: boolean;
constructor(service: Service) {
this.tasks = service.getTasks();
this.dependencies = service.getDependencies();
this.autoUpdateParentTasks = true;
this.validateDependencies = true;
this.enablePredecessorGap = true;
}
}
bootstrapApplication(AppComponent, {
providers: [
provideZoneChangeDetection({ eventCoalescing: true, runCoalescing: true }),
],
});
#gantt {
height: 700px;
}
.options {
margin-bottom: 20px;
padding: 20px;
background-color: rgba(191, 191, 191, 0.15);
position: relative;
}
.caption {
font-size: 18px;
font-weight: 500;
}
.option {
margin-top: 10px;
margin-right: 40px;
display: inline-block;
}
.option:last-child {
margin-right: 0;
}
import { Injectable } from '@angular/core';
export class Task {
id: number;
parentId: number;
title: string;
start: Date;
end: Date;
progress: number;
}
export class Dependency {
id: number;
predecessorId: number;
successorId: number;
type: number;
}
const currentDate: Date = new Date(Date.now());
const month: number = currentDate.getMonth();
const year: number = currentDate.getFullYear();
const tasks: Task[] = [{
id: 1,
parentId: 0,
title: 'Johnson Residence Construction Project',
start: new Date(year, month - 1, 1),
end: new Date(year, month - 1, 1),
progress: 0,
}, {
id: 2,
parentId: 1,
title: 'Planning and Pre-Construction Phase',
start: new Date(year, month - 1, 1),
end: new Date(year, month - 1, 1),
progress: 0,
}, {
id: 3,
parentId: 2,
title: 'Architectural Design and Site Planning',
start: new Date(year, month - 1, 1),
end: new Date(year, month - 1, 15),
progress: 0,
}, {
id: 4,
parentId: 2,
title: 'Engineering and Final Blueprint',
start: new Date(year, month - 1, 8),
end: new Date(year, month - 1, 15),
progress: 0,
}, {
id: 5,
parentId: 2,
title: 'City Permits and Contracts',
start: new Date(year, month - 1, 15),
end: new Date(year, month - 1, 18),
progress: 0,
}, {
id: 6,
parentId: 1,
title: 'Construction Phase',
start: new Date(year, month - 1, 18),
end: new Date(year, month - 1, 18),
progress: 0,
}, {
id: 7,
parentId: 6,
title: 'Grading and Excavation',
start: new Date(year, month - 1, 18),
end: new Date(year, month - 1, 22),
progress: 0,
}, {
id: 8,
parentId: 6,
title: 'Demolition and Removal',
start: new Date(year, month - 1, 19),
end: new Date(year, month - 1, 23),
progress: 0,
}, {
id: 9,
parentId: 6,
title: 'Foundation and Concrete ',
start: new Date(year, month - 1, 22),
end: new Date(year, month - 1, 28),
progress: 0,
}, {
id: 10,
parentId: 6,
title: 'Rough Framing and Carpentery',
start: new Date(year, month - 1, 25),
end: new Date(year, month, 5),
progress: 0,
}, {
id: 11,
parentId: 6,
title: 'Inspection (Structure)',
start: new Date(year, month, 5),
end: new Date(year, month, 5),
progress: 0,
}, {
id: 12,
parentId: 6,
title: 'Electrical Rough-in',
start: new Date(year, month, 6),
end: new Date(year, month, 19),
progress: 0,
}, {
id: 13,
parentId: 6,
title: 'Plumbing Rough-in',
start: new Date(year, month, 19),
end: new Date(year, month, 19),
progress: 0,
}, {
id: 14,
parentId: 6,
title: 'Heating and A/C',
start: new Date(year, month, 19),
end: new Date(year, month, 26),
progress: 0,
}, {
id: 15,
parentId: 6,
title: 'Drywall',
start: new Date(year, month, 25),
end: new Date(year, month + 1, 10),
progress: 0,
}, {
id: 16,
parentId: 6,
title: 'Painting (Exterior)',
start: new Date(year, month + 1, 7),
end: new Date(year, month + 1, 21),
progress: 0,
}, {
id: 17,
parentId: 6,
title: 'Interior Carpentery (Interior)',
start: new Date(year, month + 1, 17),
end: new Date(year, month + 1, 28),
progress: 0,
}, {
id: 18,
parentId: 6,
title: 'Flooring and Interior Paint',
start: new Date(year, month + 1, 26),
end: new Date(year, month + 2, 9),
progress: 0,
}, {
id: 19,
parentId: 1,
title: 'Final Phase',
start: new Date(year, month + 2, 9),
end: new Date(year, month + 2, 9),
progress: 0,
}, {
id: 20,
parentId: 19,
title: 'Review-Punch List',
start: new Date(year, month + 2, 9),
end: new Date(year, month + 2, 23),
progress: 0,
}, {
id: 21,
parentId: 19,
title: 'Final Inspection',
start: new Date(year, month + 2, 24),
end: new Date(year, month + 2, 24),
progress: 0,
}, {
id: 22,
parentId: 19,
title: 'Final Paperwork and Documents',
start: new Date(year, month + 2, 24),
end: new Date(year, month + 2, 28),
progress: 0,
}];
const dependencies: Dependency[] = [{
id: 1,
predecessorId: 4,
successorId: 5,
type: 0,
}, {
id: 2,
predecessorId: 5,
successorId: 7,
type: 0,
}, {
id: 3,
predecessorId: 12,
successorId: 13,
type: 0,
}, {
id: 4,
predecessorId: 13,
successorId: 14,
type: 0,
}, {
id: 5,
predecessorId: 18,
successorId: 20,
type: 0,
}, {
id: 6,
predecessorId: 21,
successorId: 22,
type: 0,
}];
@Injectable()
export class Service {
getTasks(): Task[] {
return tasks;
}
getDependencies(): Dependency[] {
return dependencies;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<title>DevExtreme Demo</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0" />
<link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/26.1.5/css/dx.light.css" />
<link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/26.1.5/css/dx-gantt.css" />
</head>
<body class="dx-viewport">
<div class="demo-container">
<demo-app>Loading...</demo-app>
</div>
<script src="https://cdn.jsdelivr.net/npm/zone.js@0.16.2/bundles/zone.umd.js"></script>
<script src="./bundle.js" type="module"></script>
</body>
</html>
The Gantt supports the following dependency validation rules:
- Finish to Start (FS) - A successor task's start point should be equal or later than the preceding task's end point.
- Start to Start (SS) - A successor task's start point should be equal or later than the preceding task's start point.
- Finish to Finish (FF) - A successor task's end point should be equal or later than the preceding task's end point.
- Start to Finish (SF) - A successor task's end point should be equal or later than a preceding task's start point.
The Gantt also has the autoUpdateParentTasks property that enables validation for parent-child relationship:
- A parent task's duration equals a summary duration of its child tasks.
- A parent task and its first child starts at the same time.
- A parent task and its last child ends at the same time.
- A parent task's progress is a summary progress of its child tasks.
The Gantt processes changes in task values before they are saved to a database. The component displays a popup window with a list of available actions if an error can be handled in several ways.