Task Constraints in EJ2 JavaScript Gantt Chart Control

2 Feb 202620 minutes to read

Task constraints in the EJ2 JavaScript Gantt Chart control define scheduling rules that control when tasks start or finish, ensuring logical sequences, fixed deadlines, and optimized resource allocation. Constraints affect taskbar positioning, dependency scheduling, and critical path calculations, making schedules realistic by accounting for limitations like material delays or compliance dates. They integrate with taskMode (e.g., Auto for automatic scheduling, Manual for fixed dates).

Benefits of task constraints

Task constraints enhance project planning with the following advantages:

  • Enforce logical task sequences, ensuring dependencies are respected (e.g., taskbars align with predecessors).
  • Anchor tasks to fixed milestone dates, such as product launches or audits.
  • Prevent resource conflicts by spacing tasks that share teams or equipment.
  • Support “what-if” scenario testing by adjusting constraints to explore timeline impacts.
  • Meet compliance deadlines, ensuring taskbars reflect regulatory requirements.
  • Improve accuracy by incorporating real-world constraints like material availability.

Understand task constraint types

The constraintType property accepts one of eight numeric values from the ConstraintType enum, each defining a specific scheduling rule. These can be specified using the corresponding numeric value (e.g., 0). The enum values are typically set in the taskFields.constraintType mapping or directly in the data source. Below is a table summarizing the constraint types, their descriptions, example use cases, and their corresponding numeric enum values:

Constraint Type Numeric Enum Value Description Example Use Case
As Soon As Possible (ASAP) 0 Starts the task as soon as dependencies are met. Default for auto-scheduled tasks. Begin coding once requirements are finalized.
As Late As Possible (ALAP) 1 Delays the task until the latest possible start without delaying successors. Finalize documentation just before release.
Must Start On (MSO) 2 Requires the task to start on a specific date. Start integration on July 1 per contract.
Must Finish On (MFO) 3 Requires the task to finish on a specific date. Submit reports by March 31 for compliance.
Start No Earlier Than (SNET) 4 Prevents the task from starting before a date. Delay marketing until regulatory approval on August 15.
Start No Later Than (SNLT) 5 Requires the task to start on or before a date. Begin reviews by September 1 for reporting.
Finish No Earlier Than (FNET) 6 Prevents the task from finishing before a date. Delay training completion until onboarding finishes.
Finish No Later Than (FNLT) 7 Requires the task to finish on or before a date. Complete QA by July 25 for release.

Configure task constraints

Configure task constraints using the taskFields.constraintType and taskFields.constraintDate properties to map constraint types and dates. Use ConstraintType enum values for clarity.

Define taskFields mappings

Map the following fields in taskFields:

  • id: Task identifier.
  • name: Task name.
  • startDate: Task start date.
  • endDate: Task end date.
  • constraintType: Constraint type (e.g., constraintType: 2 (MustStartOn)).
  • constraintDate: Date for the constraint.

Provide constraint data

Include constraintType and constraintDate in your data source. For example:

{
  "taskId": 1,
  "taskName": "Design Approval",
  "startDate": new Date("2025-07-01"),
  "endDate": new Date("2025-07-02"),
  "constraintType": 2,
  "constraintDate": new Date("2025-07-01")
}

The following example applies a MustStartOn constraint. This code sets a task to start on July 1, 2025, with the taskbar reflecting the constraint.

ej.gantt.Gantt.Inject(ej.gantt.Selection,
    ej.gantt.Toolbar,
    ej.gantt.DayMarkers,
    ej.gantt.Edit);
var ganttChart = new ej.gantt.Gantt({
    dataSource: constraintData,
    taskFields: {
        id: 'TaskID',
        name: 'TaskName',
        startDate: 'StartDate',
        endDate: 'EndDate',
        duration: 'Duration',
        progress: 'Progress',
        constraintType: 'ConstraintType',
        constraintDate: 'ConstraintDate',
        dependency: 'Predecessor',
        parentID: 'parentID',
        notes: 'info',
    },
    editSettings: {
        allowAdding: true,
        allowEditing: true,
        allowDeleting: true,
        allowTaskbarEditing: true,
        showDeleteConfirmDialog: true
    },
    toolbar: ['Add', 'Edit', 'Update', 'Delete', 'Cancel', 'ExpandAll', 'CollapseAll', 'Indent', 'Outdent'],
    allowSelection: true,
    gridLines: 'Both',
    height: '450px',
    treeColumnIndex: 1,
    highlightWeekends: true,
    timelineSettings: {
        topTier: {
            unit: 'Week',
            format: 'MMM dd, y',
        },
        bottomTier: {
            unit: 'Day',
        }
    },
    eventMarkers: [
        {
            day: new Date('03/25/2025'),
            label: 'Project StartDate'
        }, {
            day: new Date('08/31/2025'),
            label: 'Project EndDate'
        }
    ],
    columns: [
        { field: 'TaskID', visible: false },
        { field: 'TaskName', headerText: 'Job Name', width: '200', clipMode: 'EllipsisWithTooltip' },
        { field: 'StartDate' },
        { field: 'Duration' },
        { field: 'ConstraintType', width: '180' },
        { field: 'ConstraintDate' },
        { field: 'EndDate' },
        { field: 'Predecessor' },
        { field: 'Progress' },
    ],
    labelSettings: {
        leftLabel: 'TaskName',
        rightLabel: '#rightLabel',
    },
    splitterSettings: {
        columnIndex: 4
    },
    projectStartDate: new Date('03/25/2025'),
    projectEndDate: new Date('09/01/2025')
});
ganttChart.appendTo('#Gantt');
window.getConstraintText = function (value) {
    var map = {
        0: 'As Soon As Possible',
        1: 'As Late As Possible',
        2: 'Must Start On',
        3: 'Must Finish On',
        4: 'Start No Earlier Than',
        5: 'Start No Later Than',
        6: 'Finish No Earlier Than',
        7: 'Finish No Later Than'
    };
    return map[value];
};
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>EJ2 Gantt</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="Typescript Gantt Controls">
    <meta name="author" content="Syncfusion">
    <link href="index.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/32.1.19/tailwind3.css" rel="stylesheet" type="text/css">
    <script src="https://cdn.syncfusion.com/ej2/32.1.19/dist/ej2.min.js" type="text/javascript"></script>
    <script src="es5-datasource.js" type="text/javascript"></script>
  <script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.js" type ="text/javascript"></script>
</head>
  <body>
    <div id="container">
      <div id="Gantt"></div>
    </div>
    <script>
      var ele = document.getElementById('container');
      if(ele) {
        ele.style.visibility = "visible";
      }
    </script>
    <script type="text/x-template" id="rightLabel">
      <div style="margin-top:-7px;">
        <div id = "rightLabel">
          ${getConstraintText(ganttProperties.constraintType)}
        </div>
      </div>
    </script>
    <script src="index.js" type="text/javascript"></script>
  </body>
</html>

Handle constraint violations

Constraint violations occur when scheduling changes (e.g., dragging taskbars) conflict with strict constraints (MustStartOn, MustFinishOn, StartNoLaterThan, FinishNoLaterThan). By default, a validation popup alerts users. Use the actionBegin event with requestType: 'validateTaskViolation' to manage violations programmatically, setting args.validateMode flags to control behavior:

  • respectMustStartOn: Silently rejects MustStartOn violations.
  • respectMustFinishOn: Silently rejects MustFinishOn violations.
  • respectStartNoLaterThan: Silently rejects StartNoLaterThan violations.
  • respectFinishNoLaterThan: Silently rejects FinishNoLaterThan violations.

Setting a flag to true cancels updates without a popup; false (default) shows the popup. Use args.cancel in taskbarEditing for pre-edit validation.

actionBegin(args) {
    if (args.requestType === 'validateTaskViolation') {
        args.validateMode = {
            respectMustStartOn: true,
            respectMustFinishOn: true,
            respectStartNoLaterThan: true,
            respectFinishNoLaterThan: true
        };
    }
}

The following example disables the MustStartOn violation popup:

ej.gantt.Gantt.Inject(ej.gantt.Selection,
    ej.gantt.Toolbar,
    ej.gantt.DayMarkers,
    ej.gantt.Edit);
var ganttChart = new ej.gantt.Gantt({
    dataSource: constraintData,
    taskFields: {
        id: 'TaskID',
        name: 'TaskName',
        startDate: 'StartDate',
        endDate: 'EndDate',
        duration: 'Duration',
        progress: 'Progress',
        constraintType: 'ConstraintType',
        constraintDate: 'ConstraintDate',
        dependency: 'Predecessor',
        parentID: 'parentID',
        notes: 'info',
    },
    editSettings: {
        allowAdding: true,
        allowEditing: true,
        allowDeleting: true,
        allowTaskbarEditing: true,
        showDeleteConfirmDialog: true
    },
    actionBegin(args) {
        if (args.requestType === 'validateTaskViolation') {
            args.validateMode.respectMustStartOn = true
        }
    },
    toolbar: ['Add', 'Edit', 'Update', 'Delete', 'Cancel', 'ExpandAll', 'CollapseAll', 'Indent', 'Outdent'],
    allowSelection: true,
    gridLines: 'Both',
    height: '450px',
    treeColumnIndex: 1,
    highlightWeekends: true,
    timelineSettings: {
        topTier: {
            unit: 'Week',
            format: 'MMM dd, y',
        },
        bottomTier: {
            unit: 'Day',
        }
    },
    eventMarkers: [
        {
            day: new Date('03/25/2025'),
            label: 'Project StartDate'
        }, {
            day: new Date('08/31/2025'),
            label: 'Project EndDate'
        }
    ],
    columns: [
        { field: 'TaskID', visible: false },
        { field: 'TaskName', headerText: 'Job Name', width: '200', clipMode: 'EllipsisWithTooltip' },
        { field: 'StartDate' },
        { field: 'Duration' },
        { field: 'ConstraintType', width: '180' },
        { field: 'ConstraintDate' },
        { field: 'EndDate' },
        { field: 'Predecessor' },
        { field: 'Progress' },
    ],
    labelSettings: {
        leftLabel: 'TaskName',
        rightLabel: '#rightLabel',
    },
    splitterSettings: {
        columnIndex: 4
    },
    projectStartDate: new Date('03/25/2025'),
    projectEndDate: new Date('09/01/2025')
});
ganttChart.appendTo('#Gantt');
window.getConstraintText = function (value) {
    var map = {
        0: 'As Soon As Possible',
        1: 'As Late As Possible',
        2: 'Must Start On',
        3: 'Must Finish On',
        4: 'Start No Earlier Than',
        5: 'Start No Later Than',
        6: 'Finish No Earlier Than',
        7: 'Finish No Later Than'
    };
    return map[value];
};
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>EJ2 Gantt</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="Typescript Gantt Controls">
    <meta name="author" content="Syncfusion">
    <link href="index.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/32.1.19/tailwind3.css" rel="stylesheet" type="text/css">
    <script src="https://cdn.syncfusion.com/ej2/32.1.19/dist/ej2.min.js" type="text/javascript"></script>
    <script src="es5-datasource.js" type="text/javascript"></script>
  <script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.js" type ="text/javascript"></script>
</head>
  <body>
    <div id="container">
      <div id="Gantt"></div>
    </div>
    <script>
      var ele = document.getElementById('container');
      if(ele) {
        ele.style.visibility = "visible";
      }
    </script>
    <script type="text/x-template" id="rightLabel">
      <div style="margin-top=-7px;">
        <div id = "rightLabel">
          ${getConstraintText(ganttProperties.constraintType)}
        </div>
      </div>
    </script>
    <script src="index.js" type="text/javascript"></script>
  </body>
</html>

See also