Your search did not match any results.
Gantt

Validation

The DevExtreme HTML5 JavaScript Gantt widget allows you to validate relationships between tasks and handle errors. Set the enableDependencyValidation option to true to enable task validation.

The Gantt supports the following dependency validation rules:

  • Finish to Start (FS) - A successor task's start point should equal the preceding task's end point.
  • Start to Start (SS) - Successor and predecessor tasks should begin at the same time.
  • Finish to Finish (FF) - Successor and predecessor tasks should end at the same time.
  • Start to Finish (SF) - A successor task's end point should equal a preceding task's start point.

The Gantt also has the autoUpdateParentTasks option 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 widget processes changes in task values before they are saved to a database. The widget displays a popup window with a list of available actions if an error can be handled in several ways.

Copy to CodeSandBox
Apply
Reset
<template> <div id="form-demo"> <div class="options"> <div class="caption">Options</div> <div class="option"> <DxCheckBox v-model:value="autoUpdateParentTasks" text="Auto Update Parent Tasks" /> </div> <div class="option"> <DxCheckBox v-model:value="validateDependencies" text="Enable Dependency Validation" /> </div> </div> <div class="widget-container"> <DxGantt :task-list-width="500" :height="700" task-title-position="none" > <DxValidation :auto-update-parent-tasks="autoUpdateParentTasks" :validate-dependencies="validateDependencies" /> <DxTasks :data-source="tasks"/> <DxDependencies :data-source="dependencies"/> <DxEditing :enabled="true"/> <DxColumn :width="300" data-field="title" caption="Task" /> <DxColumn data-field="start" caption="Start Date" /> <DxColumn data-field="end" caption="End Date" /> </DxGantt> </div> </div> </template> <script> import { DxGantt, DxTasks, DxDependencies, DxColumn, DxEditing, DxValidation } from 'devextreme-vue/gantt'; import DxCheckBox from 'devextreme-vue/check-box'; import { tasks, dependencies } from './data.js'; export default { components: { DxGantt, DxTasks, DxDependencies, DxColumn, DxEditing, DxValidation, DxCheckBox }, data() { return { tasks: tasks, dependencies: dependencies, autoUpdateParentTasks: true, validateDependencies: true }; } }; </script> <style> #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: 44px; display: inline-block; } .option:last-child { margin-right: 0; } </style>
import { createApp } from 'vue'; import App from './App.vue'; createApp(App).mount('#app');
<!DOCTYPE html> <html> <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=1.0" /> <link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/20.2.3/css/dx.common.css" /> <link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/20.2.3/css/dx.light.css" /> <link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/20.2.3/css/dx-gantt.css" /> <script src="https://unpkg.com/core-js@2.4.1/client/shim.min.js"></script> <script src="https://unpkg.com/systemjs@0.21.3/dist/system.js"></script> <script type="text/javascript" src="config.js"></script> <script type="text/javascript"> System.import('./index.js'); </script> </head> <body class="dx-viewport"> <div class="demo-container"> <div id="app"> </div> </div> </body> </html>
const currentDate = new Date(Date.now()); const month = currentDate.getMonth(); const year = currentDate.getFullYear(); export const tasks = [{ '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, 29), '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, 29), '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, 30), 'progress': 0 }]; export const dependencies = [{ '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 }];
System.config({ transpiler: 'plugin-babel', meta: { '*.vue': { loader: 'vue-loader' }, }, paths: { 'npm:': 'https://unpkg.com/' }, map: { 'vue': 'npm:vue@3.0.0/dist/vue.esm-browser.js', 'vue-loader': 'npm:dx-systemjs-vue-browser@1.0.15/index.js', 'mitt': 'npm:mitt/dist/mitt.umd.js', 'rrule': 'npm:rrule@2.6.6/dist/es5/rrule.js', 'luxon': 'npm:luxon@1.25.0/build/global/luxon.min.js', 'es6-object-assign': 'npm:es6-object-assign@1.1.0', 'devextreme': 'npm:devextreme@20.2.3', 'devextreme-vue': 'npm:devextreme-vue@20.2.3', 'jszip': 'npm:jszip@3.5.0/dist/jszip.min.js', 'devextreme-quill': 'npm:devextreme-quill@0.9.5/dist/dx-quill.min.js', 'devexpress-diagram': 'npm:devexpress-diagram@2.0.0/dist/dx-diagram.js', 'devexpress-gantt': 'npm:devexpress-gantt@2.0.0/dist/dx-gantt.js', 'preact': 'npm:preact@10.5.5/dist/preact.js', 'preact/hooks': 'npm:preact@10.5.5/hooks/dist/hooks.js', 'plugin-babel': 'npm:systemjs-plugin-babel@0.0.25/plugin-babel.js', 'systemjs-babel-build': 'npm:systemjs-plugin-babel@0.0.25/systemjs-babel-browser.js' }, packages: { 'devextreme-vue': { main: 'index.js' }, 'devextreme': { defaultExtension: 'js' }, 'devextreme/events/utils': { main: 'index' }, 'devextreme/events': { main: 'index' }, 'es6-object-assign': { main: './index.js', defaultExtension: 'js' } }, babelOptions: { sourceMaps: false, stage0: true } });