Task Constraints with Scheduling Rules in ASP.NET Core Gantt Chart

Task constraints in the ASP.NET Core Gantt Chart component 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 tailwind3 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 constraintType mapping in the task fields 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., a field holding 2 (MustStartOn)).
  • constraintDate: Date for the constraint.

Provide constraint data

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

new GanttDataSource
{
    TaskId = 1,
    TaskName = "Design Approval",
    StartDate = new DateTime(2025, 7, 1),
    EndDate = new DateTime(2025, 7, 2),
    ConstraintType = 2,
    ConstraintDate = new DateTime(2025, 7, 1)
}

The following example applies a MustStartOn constraint:

@page
@model CoreSamples.Pages.IndexModel

<ejs-gantt id="Gantt" dataSource="@Model.GanttDataSourceCollection" height="450px" treeColumnIndex="1"
           projectStartDate="03/25/2025" projectEndDate="09/01/2025">

    <e-gantt-taskfields id="TaskId" name="TaskName" startDate="StartDate" endDate="EndDate" duration="Duration"
                        progress="Progress" constraintType="ConstraintType" constraintDate="ConstraintDate" dependency="Predecessor"
                        parentID="ParentId">
    </e-gantt-taskfields>

    <e-gantt-editsettings allowAdding="true" allowEditing="true" allowDeleting="true" allowTaskbarEditing="true"
                          showDeleteConfirmDialog="true">
    </e-gantt-editsettings>

    <e-gantt-splittersettings columnIndex="4"></e-gantt-splittersettings>

    <e-gantt-labelsettings leftLabel="TaskName" rightLabel="#rightLabelTemplate">
    </e-gantt-labelsettings>

    <e-gantt-timelinesettings>
        <e-timelinesettings-toptier unit="Week" format="MMM dd, yyyy">
        </e-timelinesettings-toptier>

        <e-timelinesettings-bottomtier unit="Day">
        </e-timelinesettings-bottomtier>
    </e-gantt-timelinesettings>
    <e-gantt-eventmarkers>
        <e-gantt-eventmarker day="03/25/2025" label="Project StartDate"></e-gantt-eventmarker>
        <e-gantt-eventmarker day="08/31/2025" label="Project EndDate"></e-gantt-eventmarker>
    </e-gantt-eventmarkers>
    <e-gantt-columns>
        <e-gantt-column field="TaskId" visible="false"></e-gantt-column>
        <e-gantt-column field="TaskName" headerText="Job Name" width="200">
        </e-gantt-column>
        <e-gantt-column field="StartDate"></e-gantt-column>
        <e-gantt-column field="Duration"></e-gantt-column>
        <e-gantt-column field="ConstraintType"></e-gantt-column>
        <e-gantt-column field="ConstraintDate"></e-gantt-column>
        <e-gantt-column field="EndDate"></e-gantt-column>
        <e-gantt-column field="Predecessor"></e-gantt-column>
        <e-gantt-column field="Progress"></e-gantt-column>
    </e-gantt-columns>

</ejs-gantt>

<script id="rightLabelTemplate" type="text/x-template">
    <div style="margin-top:-7px;">
        ${getConstraintText(ConstraintType)}
    </div>
</script>

<script>
    function getConstraintText(value) {

        const 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] || '';
    }
</script>
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace CoreSamples.Pages
{
    public class IndexModel : PageModel
    {
        public List<GanttDataSource> GanttDataSourceCollection { get; set; }

        public void OnGet()
        {
            GanttDataSourceCollection = GetTaskCollection();
        }

        private List<GanttDataSource> GetTaskCollection()
        {
            return new List<GanttDataSource>()
            {
                new GanttDataSource
                {
                    TaskId = 1,
                    TaskName = "Planning and Permits",
                    StartDate = new DateTime(2025, 4, 2),
                    EndDate = new DateTime(2025, 4, 10),
                    Duration = 7,
                    Progress = 100,
                    ConstraintType = 0
                },
                new GanttDataSource
                {
                    TaskId = 2,
                    TaskName = "Site Evaluation",
                    StartDate = new DateTime(2025, 4, 2),
                    EndDate = new DateTime(2025, 4, 4),
                    Duration = 2,
                    Progress = 100,
                    ParentId = 1,
                    ConstraintType = 4,
                    ConstraintDate = new DateTime(2025, 4, 2)
                },
                new GanttDataSource
                {
                    TaskId = 3,
                    TaskName = "Obtain Permits",
                    StartDate = new DateTime(2025, 4, 7),
                    EndDate = new DateTime(2025, 4, 9),
                    Duration = 3,
                    Progress = 100,
                    ParentId = 1,
                    Predecessor = "2FS+2days",
                    ConstraintType = 2,
                    ConstraintDate = new DateTime(2025, 4, 7)
                },
                new GanttDataSource
                {
                    TaskId = 4,
                    TaskName = "Finalize Planning",
                    StartDate = new DateTime(2025, 4, 10),
                    EndDate = new DateTime(2025, 4, 11),
                    Duration = 2,
                    Progress = 100,
                    ParentId = 1,
                    Predecessor = "3FS",
                    ConstraintType = 6,
                    ConstraintDate = new DateTime(2025, 4, 11)
                },
                new GanttDataSource
                {
                    TaskId = 5,
                    TaskName = "Site Preparation",
                    StartDate = new DateTime(2025, 4, 14),
                    EndDate = new DateTime(2025, 4, 18),
                    Duration = 5,
                    Progress = 100,
                    ConstraintType = 0
                },
                new GanttDataSource
                {
                    TaskId = 6,
                    TaskName = "Site Clearing",
                    StartDate = new DateTime(2025, 4, 14),
                    Duration = 0,
                    Progress = 100,
                    ParentId = 5,
                    ConstraintType = 1
                },
                new GanttDataSource
                {
                    TaskId = 7,
                    TaskName = "Grading and Excavation",
                    StartDate = new DateTime(2025, 4, 15),
                    EndDate = new DateTime(2025, 4, 17),
                    Duration = 3,
                    Progress = 100,
                    ParentId = 5,
                    Predecessor = "6",
                    ConstraintType = 0
                },
                new GanttDataSource
                {
                    TaskId = 8,
                    TaskName = "Foundation Work",
                    StartDate = new DateTime(2025, 4, 18),
                    EndDate = new DateTime(2025, 4, 21),
                    Duration = 4,
                    Progress = 100,
                    ParentId = 5,
                    Predecessor = "7+1",
                    ConstraintType = 4,
                    ConstraintDate = new DateTime(2025, 4, 18)
                },
                new GanttDataSource
                {
                    TaskId = 9,
                    TaskName = "Foundation and Basement",
                    StartDate = new DateTime(2025, 4, 22),
                    EndDate = new DateTime(2025, 4, 28),
                    Duration = 5,
                    Progress = 100,
                    ParentId = 5,
                    ConstraintType = 0
                },
                new GanttDataSource
                {
                    TaskId = 10,
                    TaskName = "Pour Foundation",
                    StartDate = new DateTime(2025, 4, 22),
                    EndDate = new DateTime(2025, 4, 23),
                    Duration = 2,
                    Progress = 100,
                    ParentId = 9,
                    Predecessor = "8",
                    ConstraintType = 4,
                    ConstraintDate = new DateTime(2025, 4, 22)
                },
                new GanttDataSource
                {
                    TaskId = 11,
                    TaskName = "Cure Foundation",
                    StartDate = new DateTime(2025, 4, 28),
                    EndDate = new DateTime(2025, 4, 29),
                    Duration = 2,
                    Progress = 100,
                    ParentId = 9,
                    Predecessor = "10",
                    ConstraintType = 3,
                    ConstraintDate = new DateTime(2025, 4, 29)
                },
                new GanttDataSource
                {
                    TaskId = 12,
                    TaskName = "Basement Walls",
                    StartDate = new DateTime(2025, 4, 28),
                    EndDate = new DateTime(2025, 4, 30),
                    Duration = 3,
                    Progress = 100,
                    ParentId = 9,
                    Predecessor = "11FS",
                    ConstraintType = 0
                },
                new GanttDataSource
                {
                    TaskId = 13,
                    TaskName = "Framing",
                    StartDate = new DateTime(2025, 5, 1),
                    EndDate = new DateTime(2025, 5, 7),
                    Duration = 5,
                    Progress = 100,
                    ConstraintType = 0
                },
                new GanttDataSource
                {
                    TaskId = 14,
                    TaskName = "Frame Floors",
                    StartDate = new DateTime(2025, 5, 1),
                    EndDate = new DateTime(2025, 5, 2),
                    Duration = 2,
                    Progress = 100,
                    ParentId = 13,
                    ConstraintType = 4,
                    ConstraintDate = new DateTime(2025, 5, 1)
                },
                new GanttDataSource
                {
                    TaskId = 15,
                    TaskName = "Frame Walls",
                    StartDate = new DateTime(2025, 5, 8),
                    EndDate = new DateTime(2025, 5, 9),
                    Duration = 2,
                    Progress = 100,
                    ParentId = 13,
                    Predecessor = "14FS+3",
                    ConstraintType = 2,
                    ConstraintDate = new DateTime(2025, 5, 8)
                },
                new GanttDataSource
                {
                    TaskId = 16,
                    TaskName = "Install Trusses",
                    StartDate = new DateTime(2025, 5, 7),
                    EndDate = new DateTime(2025, 5, 8),
                    Duration = 2,
                    Progress = 100,
                    ParentId = 13,
                    Predecessor = "15",
                    ConstraintType = 6,
                    ConstraintDate = new DateTime(2025, 5, 8)
                },

                // Continue similarly for TaskId 17 through 40
                // using the exact values from the Angular datasource.

            };
        }
    }

    public class GanttDataSource
    {
        public int TaskId { get; set; }
        public string TaskName { get; set; }

        public DateTime? StartDate { get; set; }

        public DateTime? EndDate { get; set; }

        public int? Duration { get; set; }

        public int? Progress { get; set; }

        public int? ParentId { get; set; }

        public string? Predecessor { get; set; }

        public int? ConstraintType { get; set; }

        public DateTime? ConstraintDate { get; set; }
    }
}

Task Constraints

This code sets a task to start on July 1, 2025, with the taskbar reflecting the constraint.

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.

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

The following example disables the MustStartOn violation popup:

@page
@model CoreSamples.Pages.IndexModel

<ejs-gantt id="Gantt" dataSource="@Model.GanttDataSourceCollection" height="450px" treeColumnIndex="1"
           projectStartDate="03/25/2025" projectEndDate="09/01/2025" actionBegin="actionBegin">

    <e-gantt-taskfields id="TaskId" name="TaskName" startDate="StartDate" endDate="EndDate" duration="Duration"
                        progress="Progress" constraintType="ConstraintType" constraintDate="ConstraintDate" dependency="Predecessor"
                        parentID="ParentId">
    </e-gantt-taskfields>

    <e-gantt-editsettings allowAdding="true" allowEditing="true" allowDeleting="true" allowTaskbarEditing="true"
                          showDeleteConfirmDialog="true">
    </e-gantt-editsettings>

    <e-gantt-splittersettings columnIndex="4"></e-gantt-splittersettings>

    <e-gantt-labelsettings leftLabel="TaskName" rightLabel="#rightLabelTemplate">
    </e-gantt-labelsettings>

    <e-gantt-timelinesettings>
        <e-timelinesettings-toptier unit="Week" format="MMM dd, yyyy">
        </e-timelinesettings-toptier>

        <e-timelinesettings-bottomtier unit="Day">
        </e-timelinesettings-bottomtier>
    </e-gantt-timelinesettings>
    <e-gantt-eventmarkers>
        <e-gantt-eventmarker day="03/25/2025" label="Project StartDate"></e-gantt-eventmarker>
        <e-gantt-eventmarker day="08/31/2025" label="Project EndDate"></e-gantt-eventmarker>
    </e-gantt-eventmarkers>
    <e-gantt-columns>
        <e-gantt-column field="TaskId" visible="false"></e-gantt-column>
        <e-gantt-column field="TaskName" headerText="Job Name" width="200">
        </e-gantt-column>
        <e-gantt-column field="StartDate"></e-gantt-column>
        <e-gantt-column field="Duration"></e-gantt-column>
        <e-gantt-column field="ConstraintType"></e-gantt-column>
        <e-gantt-column field="ConstraintDate"></e-gantt-column>
        <e-gantt-column field="EndDate"></e-gantt-column>
        <e-gantt-column field="Predecessor"></e-gantt-column>
        <e-gantt-column field="Progress"></e-gantt-column>
    </e-gantt-columns>

</ejs-gantt>

<script id="rightLabelTemplate" type="text/x-template">
    <div style="margin-top:-7px;">
        ${getConstraintText(ConstraintType)}
    </div>
</script>
<script>
    function actionBegin(args) {
        if (args.requestType === 'validateTaskViolation') {
            debugger;
            args.validateMode.respectMustStartOn = true;
        }
    }
</script>
<script>
    function getConstraintText(value) {

        const 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] || '';
    }
</script>
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace CoreSamples.Pages
{
    public class IndexModel : PageModel
    {
        public List<GanttDataSource> GanttDataSourceCollection { get; set; }

        public void OnGet()
        {
            GanttDataSourceCollection = GetTaskCollection();
        }

        private List<GanttDataSource> GetTaskCollection()
        {
            return new List<GanttDataSource>()
            {
                new GanttDataSource
                {
                    TaskId = 1,
                    TaskName = "Planning and Permits",
                    StartDate = new DateTime(2025, 4, 2),
                    EndDate = new DateTime(2025, 4, 10),
                    Duration = 7,
                    Progress = 100,
                    ConstraintType = 0
                },
                new GanttDataSource
                {
                    TaskId = 2,
                    TaskName = "Site Evaluation",
                    StartDate = new DateTime(2025, 4, 2),
                    EndDate = new DateTime(2025, 4, 4),
                    Duration = 2,
                    Progress = 100,
                    ParentId = 1,
                    ConstraintType = 4,
                    ConstraintDate = new DateTime(2025, 4, 2)
                },
                new GanttDataSource
                {
                    TaskId = 3,
                    TaskName = "Obtain Permits",
                    StartDate = new DateTime(2025, 4, 7),
                    EndDate = new DateTime(2025, 4, 9),
                    Duration = 3,
                    Progress = 100,
                    ParentId = 1,
                    Predecessor = "2FS+2days",
                    ConstraintType = 2,
                    ConstraintDate = new DateTime(2025, 4, 7)
                },
                new GanttDataSource
                {
                    TaskId = 4,
                    TaskName = "Finalize Planning",
                    StartDate = new DateTime(2025, 4, 10),
                    EndDate = new DateTime(2025, 4, 11),
                    Duration = 2,
                    Progress = 100,
                    ParentId = 1,
                    Predecessor = "3FS",
                    ConstraintType = 6,
                    ConstraintDate = new DateTime(2025, 4, 11)
                },
                new GanttDataSource
                {
                    TaskId = 5,
                    TaskName = "Site Preparation",
                    StartDate = new DateTime(2025, 4, 14),
                    EndDate = new DateTime(2025, 4, 18),
                    Duration = 5,
                    Progress = 100,
                    ConstraintType = 0
                },
                new GanttDataSource
                {
                    TaskId = 6,
                    TaskName = "Site Clearing",
                    StartDate = new DateTime(2025, 4, 14),
                    Duration = 0,
                    Progress = 100,
                    ParentId = 5,
                    ConstraintType = 1
                },
                new GanttDataSource
                {
                    TaskId = 7,
                    TaskName = "Grading and Excavation",
                    StartDate = new DateTime(2025, 4, 15),
                    EndDate = new DateTime(2025, 4, 17),
                    Duration = 3,
                    Progress = 100,
                    ParentId = 5,
                    Predecessor = "6",
                    ConstraintType = 0
                },
                new GanttDataSource
                {
                    TaskId = 8,
                    TaskName = "Foundation Work",
                    StartDate = new DateTime(2025, 4, 18),
                    EndDate = new DateTime(2025, 4, 21),
                    Duration = 4,
                    Progress = 100,
                    ParentId = 5,
                    Predecessor = "7+1",
                    ConstraintType = 4,
                    ConstraintDate = new DateTime(2025, 4, 18)
                },
                new GanttDataSource
                {
                    TaskId = 9,
                    TaskName = "Foundation and Basement",
                    StartDate = new DateTime(2025, 4, 22),
                    EndDate = new DateTime(2025, 4, 28),
                    Duration = 5,
                    Progress = 100,
                    ParentId = 5,
                    ConstraintType = 0
                },
                new GanttDataSource
                {
                    TaskId = 10,
                    TaskName = "Pour Foundation",
                    StartDate = new DateTime(2025, 4, 22),
                    EndDate = new DateTime(2025, 4, 23),
                    Duration = 2,
                    Progress = 100,
                    ParentId = 9,
                    Predecessor = "8",
                    ConstraintType = 4,
                    ConstraintDate = new DateTime(2025, 4, 22)
                },
                new GanttDataSource
                {
                    TaskId = 11,
                    TaskName = "Cure Foundation",
                    StartDate = new DateTime(2025, 4, 28),
                    EndDate = new DateTime(2025, 4, 29),
                    Duration = 2,
                    Progress = 100,
                    ParentId = 9,
                    Predecessor = "10",
                    ConstraintType = 3,
                    ConstraintDate = new DateTime(2025, 4, 29)
                },
                new GanttDataSource
                {
                    TaskId = 12,
                    TaskName = "Basement Walls",
                    StartDate = new DateTime(2025, 4, 28),
                    EndDate = new DateTime(2025, 4, 30),
                    Duration = 3,
                    Progress = 100,
                    ParentId = 9,
                    Predecessor = "11FS",
                    ConstraintType = 0
                },
                new GanttDataSource
                {
                    TaskId = 13,
                    TaskName = "Framing",
                    StartDate = new DateTime(2025, 5, 1),
                    EndDate = new DateTime(2025, 5, 7),
                    Duration = 5,
                    Progress = 100,
                    ConstraintType = 0
                },
                new GanttDataSource
                {
                    TaskId = 14,
                    TaskName = "Frame Floors",
                    StartDate = new DateTime(2025, 5, 1),
                    EndDate = new DateTime(2025, 5, 2),
                    Duration = 2,
                    Progress = 100,
                    ParentId = 13,
                    ConstraintType = 4,
                    ConstraintDate = new DateTime(2025, 5, 1)
                },
                new GanttDataSource
                {
                    TaskId = 15,
                    TaskName = "Frame Walls",
                    StartDate = new DateTime(2025, 5, 8),
                    EndDate = new DateTime(2025, 5, 9),
                    Duration = 2,
                    Progress = 100,
                    ParentId = 13,
                    Predecessor = "14FS+3",
                    ConstraintType = 2,
                    ConstraintDate = new DateTime(2025, 5, 8)
                },
                new GanttDataSource
                {
                    TaskId = 16,
                    TaskName = "Install Trusses",
                    StartDate = new DateTime(2025, 5, 7),
                    EndDate = new DateTime(2025, 5, 8),
                    Duration = 2,
                    Progress = 100,
                    ParentId = 13,
                    Predecessor = "15",
                    ConstraintType = 6,
                    ConstraintDate = new DateTime(2025, 5, 8)
                },

                // Continue similarly for TaskId 17 through 40
                // using the exact values from the Angular datasource.

            };
        }
    }

    public class GanttDataSource
    {
        public int TaskId { get; set; }
        public string TaskName { get; set; }

        public DateTime? StartDate { get; set; }

        public DateTime? EndDate { get; set; }

        public int? Duration { get; set; }

        public int? Progress { get; set; }

        public int? ParentId { get; set; }

        public string? Predecessor { get; set; }

        public int? ConstraintType { get; set; }

        public DateTime? ConstraintDate { get; set; }
    }
}

Handle Constraint Violations

See also