ProjectModel
This class represents a global project of your Project plan or Gantt - a central place for all data.
It holds and links the stores used by Gantt:
The project has an internal scheduling engine to calculate dates, durations and such. It is also responsible for handling references between models, for example to link a task to a resource (via an assignment). These operations are asynchronous, a fact that is hidden when working in the Gantt UI but which you must know about when performing data level operations.
Task Scheduling
Without constraints in the dataset there is nothing pinning the tasks to their date, and they will be rescheduled as
soon as possible, i.e. at the project start date. To avoid this, simply set autoSetConstraints to true on the
ProjectModel config object. This ensures tasks remain on their specified start dates, providing a more accurate
project timeline.
project : {
autoSetContraints : true
}
With that, if you use the following data, it will show the tasks at their startDate.
[{
"id" : 1,
"name" : "Project Initiation",
"percentDone" : 100,
"duration" : 5,
"startDate" : "2024-06-03"
},
{
"id" : 2,
"name" : "Requirements Gathering",
"percentDone" : 80,
"duration" : 10,
"startDate" : "2024-06-10"
},
{
"id" : 3,
"name" : "Design Phase",
"percentDone" : 60,
"duration" : 15,
"startDate" : "2024-06-24"
}]
More about this topic can be found in the Gantt scheduling guide
To see it in action, check out the auto constraints demo.
When there is a change to data that requires something else to be recalculated, the project schedules a calculation (a commit) which happens moments later. It is also possible to trigger these calculations directly. This flow illustrates the process:
- Something changes which requires the project to recalculate, for example adding a new task:
const [task] = project.taskStore.add({ startDate, endDate });
- A recalculation is scheduled, thus:
task.duration; // <- Not yet calculated
- Calculate now instead of waiting for the scheduled calculation
await project.commitAsync();
task.duration; // <- Now available
Please refer to this guide for more information.
Built-in CrudManager
Gantt's project has a CrudManager built-in. Using it is the recommended way of syncing data between Gantt and a backend. Example usage:
const gantt = new Gantt({
project : {
// Configure urls used by the built-in CrudManager
transport : {
load : {
url : 'php/load.php'
},
sync : {
url : 'php/sync.php'
}
}
}
});
// Load data from the backend
gantt.project.load()
URLs may also be specified using shortcut configs:
const gantt = new Gantt({
project : {
loadUrl : 'php/load.php'
syncUrl : 'php/sync.php'
}
});
gantt.project.load()
For more information on CrudManager, see Schedulers docs on CrudManager. For a detailed description of the protocol used by CrudManager, please see the Crud manager guide
You can access the current Project data changes anytime using the changes property.
Working with inline data
The project provides an inlineData getter/setter that can be used to manage data from all Project stores at once. Populating the stores this way can be useful if you do not want to use the CrudManager for server communication but instead load data using Axios or similar.
Getting data
const data = gantt.project.inlineData;
// use the data in your application
Setting data
// Get data from server manually
const data = await axios.get('/project?id=12345');
// Feed it to the project
gantt.project.inlineData = data;
See also loadInlineData
Getting changed records
You can access the changes in the current Project dataset anytime using the changes property. It returns an object with all changes:
const changes = project.changes;
console.log(changes);
The changes object has the following structure:
{
tasks : {
updated : [{
name : 'My task',
id : 12
}]
},
assignments : {
added : [{
event : 12,
resource : 7,
units : 100,
$PhantomId : 'abc123'
}]
}
};
Monitoring data changes
While it is possible to listen for data changes on the projects individual stores, it is sometimes more convenient to have a centralized place to handle all data changes. By listening for the change event your code gets notified when data in any of the stores changes. Useful for example to keep an external data model up to date:
const gantt = new Gantt({
project: {
listeners : {
change({ store, action, records }) {
const { $name } = store.constructor;
if (action === 'add') {
externalDataModel.add($name, records);
}
if (action === 'remove') {
externalDataModel.remove($name, records);
}
}
}
}
});
Processing the data loaded from the server
If you want to process the data received from the server after loading, you can use the beforeLoadApply or beforeSyncApply events:
const gantt = new Gantt({
project: {
listeners : {
beforeLoadApply({ response }) {
// do something with load-response object before it is provided to all the project stores
}
}
}
});
Built-in StateTrackingManager
The project also has a built-in StateTrackingManager (STM for short), that handles undo/redo for the project stores (additional stores can also be added). By default, it is only used while editing tasks using the task editor, the editor updates tasks live and uses STM to rollback changes if canceled. But you can enable it to track all project store changes:
// Enable automatic transaction creation and start recording
project.stm.autoRecord = true;
project.stm.enable();
// Undo a transaction
project.stm.undo();
// Redo
project.stm.redo();
Check out the undoredo demo to see it in action.
Configs
53
Configs
53Common
When set to true, pins a task at its starting date. Otherwise, it is rescheduled to the
project's starting date if there is no predecessor or constraint supplied.
When a dataset is loaded without using any constraints, dependencies, or manually scheduled tasks, the
tasks are moved to the project's start date. Setting autoSetConstraints to true avoids this
behaviour by showing your tasks based on their startDate and endDate.
To see it in action, check out the auto constraints demo.
By default, the stores of a project use the raw data objects passed to them as the data source for their
records if data is loaded remotely (using an AjaxStore or a CrudManager). For data supplied inline,
the data objects are instead by default cloned to avoid the original data object being modified by the
store.
See useRawData for more information on the mechanics of this.
This can be explicitly controlled per store by setting the useRawData config on the store:
// Opt in for a single store
const project = new ProjectModel({
eventStore : {
useRawData : true
},
...
});
Or you can control it for all the default stores in the project by setting this config on the project:
// Opt in for all stores in the project
const project = new ProjectModel({
useRawData : true,
...
});
Advanced
This config manages DST correction in the scheduling engine. It only has effect when DST transition hour is working time. Usually DST transition occurs on Sunday, so with non working weekends the DST correction logic is not involved.
If true, it will add/remove one hour when calculating duration from start/end dates. For example: Assume weekends are working and on Sunday, 2020-10-25 at 03:00 clocks are set back 1 hour. Assume there is a task:
{
startDate : '2020-10-20',
duration : 10,
durationUnit : 'day'
}
It will end on 2020-10-29 23:00. Because of the DST transition Sunday is actually 25 hours long and when the Gantt project calculates the end date it converts days to hours multiplying by 24. If you're setting duration and want task to end on the end of the day you should manually correct for DST, like so:
{
startDate : '2020-10-20',
duration : 10 * 24 + 1,
durationUnit : 'hour'
},
If task has start and end dates it will correct for DST twice:
{
startDate : '2020-10-20',
endDate : '2020-10-30'
}
This task will end on 2020-10-29 22:00 which is a known quirk.
If false, the Gantt project will not add DST correction which fixes the quirk mentioned above and such task will end on 2020-10-30 exactly, having hours duration of 10 days * 24 hours + 1 hour.
Also, for this task days duration will be a floating point number due to extra (or missing) hour:
task.getDuration('day') // 10.041666666666666
task.getDuration('hour') // 241
Enables early rendering in Gantt, by postponing calculations to after the first refresh.
Requires task data loaded in Gantt to be pre-normalized to function as intended, since it will be used to render tasks before engine has normalized the data. Given un-normalized data tasks will snap into place when calculations are finished.
The Gantt chart will be read-only until the initial calculations are finished.
Set to true to enable calculation progress notifications.
When enabled, the project fires progress events and the Gantt chart load mask reacts by showing a progress bar for the Engine calculations.
Note: Enabling progress notifications will impact calculation performance, since it needs to pause calculations to allow the UI to redraw.
Maximum range the project calendars can iterate.
The value is defined in milliseconds and by default equals 5 years roughly.
new Gantt({
project : {
// adjust calendar iteration limit to 10 years roughly:
// 10 years expressed in ms
maxCalendarRange : 10 * 365 * 24 * 3600000,
...
}
});
Setting this to true (default) vetoes silenceInitialCommit effect
by preventing silent changes accepting
on initial data loading if some scheduling issue gets resolved during it.
Enabling this config allows an application to persist the data in a resolved state.
Set to true to reset the undo/redo queues of the internal StateTrackingManager
after the Project has loaded. Defaults to false
Experimental hook that lets the app determine if a bound dataset needs syncing with the store or not, and
if it does - which records that should be processed. Only called for stores that are configured with
syncDataOnLoad: true (which is the default in the React, Angular and Vue wrappers).
The main use case for this is for frameworks that update all state on any state change (like React), to not have to reapply the full bound dataset each time (which becomes costly).
If the app has a cheap way of determining (for example using a timestamp) that the dataset has no
changes, return false from this hook to prevent the store from syncing at all at that time.
shouldSyncDataOnLoad({ store, data }) {
if (store === myEventStore && timestamp <= lastUpdateTimestamp) {
// Prevent sync when the event store has not changed since last time
// (pseudocode)
return false;
}
}
If the app knows that something has changed, return a Set with ids for the records that should be
further processed by the sync logic.
shouldSyncDataOnLoad({ store, data }) {
if (store === myEventStore && timestamp > lastUpdateTimestamp) {
// Sync only these records (pseudocode)
return new Set([6, 110, 586]);
}
}
| Parameter | Type | Description |
|---|---|---|
options | Object | Options passed by the store to this hook |
options.store | Store | Store about to be synced |
options.records | Model | Records currently in the store |
options.data | Object[] | Incoming data |
Return false to prevent the store from syncing, or a set of
record ids that need further processing (for records that has some kind of change, eg. an update, removal
or addition)
Silences propagations caused by the project loading.
Applying the loaded data to the project occurs in two basic stages:
- Data gets into the engine graph which triggers changes propagation
- The changes caused by the propagation get written to related stores
Setting this flag to true makes the component perform step 2 silently without triggering events causing reactions on those changes
(like sending changes back to the server if autoSync is enabled) and keeping stores in unmodified state.
This is safe if the loaded data is consistent so propagation doesn't really do any adjustments.
By default the system treats the data as consistent so this option is true.
new Gantt({
project : {
// We want scheduling engine to recalculate the data properly
// so then we could save it back to the server
silenceInitialCommit : false,
...
}
...
})
Configuration options to provide to the STM manager
Set to a IANA time zone (i.e. Europe/Stockholm) or a UTC offset in minutes (i.e. -120). This will
convert all events, tasks and time ranges to the specified time zone or offset. It will also affect the
displayed timeline's headers as well at the start and end date of it.
There is currently no built-in time zone support in JavaScript which means that the converted dates technically still are in the local system time zone, but adjusted to match the configured time zone.
DST
If a IANA time zone is provided, there will be support for DST. But if local system time zone has DST that will affect the time zone conversion at the exact hour when the local system time zone switches DST on and off.
For example:
- The local system time zone is
Europe/Stockholm(which is UTC+1 or UTC+2 when DST). - The date
2022-03-27T07:00:00Z(which is UTC) is converted toAmerica/Chicago(which is UTC-6 or UTC-5 when DST). - The converted JS date will be created from
2022-03-27T02:00:00which is exactly the hour whenEurope/Stockholmadds an DST hour. This has the effect that the converted date shows up incorrectly as2022-03-27T03:00instead.
If a UTC offset is provided, there is no DST support at all.
Editing
If creating new records or editing existing record dates, the dates will be interpreted as in the selected time zone.
If you want to create new records with dates that either should be interpreted as local system time zone or from any other time zone, specify the timeZone field on the record.
Saving
When saving or syncing data, the dates will be restored to local system time and converted to JSON
ISO formatted. When restoring, it adds or subtracts the time difference accordingly.
For instance, if the current timezone is UTC and you're in UTC +3, 3 hours will be added to the time.
The store.toJSON() and model.toJSON() methods also restores the data. For example, eventStore.toJSON()
will show the dates in local timezone.
Inline data
Data use to fill the assignmentStore. Should be an array of AssignmentModels or its configuration objects.
Data use to fill the calendarManagerStore. Should be a CalendarModel array or its configuration objects.
Data use to fill the dependencyStore. Should be an array of DependencyModels or its configuration objects.
Project data as a JSON string, used to populate its stores.
const project = new ProjectModel({
json : '{"events":[...],"resources":[...],...}'
}
xxData properties are deprecated and will be removed in the future. Use xx instead. For
example eventsData is deprecated, use events instead. For now, both naming schemes are included in
the data object
Data use to fill the resourceStore. Should be an array of ResourceModels or its configuration objects.
Data use to fill the taskStore. Should be an array of TaskModels or its configuration objects.
Data use to fill the timeRangeStore. Should be an array of TimeRangeModels or its configuration objects.
Specifies the output format of toJSON.
inlineData- Return all crud store data, plus this project fields (under theprojectkey). For example:
{
"project" : {
"startDate" : "2024-03-22",
"endDate" : "2024-04-22",
"hoursPerDay" : 8,
"daysPerWeek" : 5,
"daysPerMonth" : 20
},
"events" : [...],
"resources" : [...],
"assignments" : [...],
"dependencies" : [...],
"resourceTimeRanges" : [...],
"timeRanges" : [...]
}
model- Return only the project fields. For example:
{
"startDate" : "2024-03-22",
"endDate" : "2024-04-22",
"hoursPerDay" : 8,
"daysPerWeek" : 5,
"daysPerMonth" : 20
}
Legacy inline data
The initial data, to fill the assignmentStore with. Should be an array of AssignmentModels or configuration objects.
The initial data, to fill the calendarManagerStore with. Should be an array of CalendarModels or configuration objects.
The initial data, to fill the dependencyStore with. Should be an array of DependencyModels or configuration objects.
Alias to tasksData.
Whether to include legacy data properties in the JSON / inlineData output. The legacy data properties are
the xxData (eventsData, resourcesData etc.) properties that are deprecated and will be removed in
the future.
The initial data, to fill the resourceStore with. Should be an array of ResourceModels or configuration objects.
The initial data, to fill the taskStore with. Should be an array of TaskModels or configuration objects.
The initial data, to fill the timeRangeStore with. Should be an array of TimeRangeModels or configuration objects.
Models & Stores
The constructor of the assignment model class, to be used in the project. Will be set as the modelClass property of the assignmentStore
An AssignmentStore instance or a config object.
The constructor to create a dependency store instance with. Should be a class, subclassing the AssignmentStore
A CalendarManagerStore instance or a config object.
The constructor to create a calendar store instance with. Should be a class, subclassing the CalendarManagerStore
The constructor of the calendar model class, to be used in the project. Will be set as the modelClass property of the calendarManagerStore
The constructor of the dependency model class, to be used in the project. Will be set as the modelClass property of the dependencyStore
A DependencyStore instance or a config object.
The constructor to create a dependency store instance with. Should be a class, subclassing the DependencyStore
A TaskStore instance or a config object.
The constructor of the resource model class, to be used in the project. Will be set as the modelClass property of the resourceStore
A ResourceStore instance or a config object.
The constructor to create a dependency store instance with. Should be a class, subclassing the ResourceStore
The constructor of the event model class, to be used in the project. Will be set as the modelClass property of the eventStore
An alias for the eventStore.
The constructor to create an task store instance with. Should be a class, subclassing the TaskStore
Store that holds time ranges - instances of TimeRangeModel for the TimeRanges feature. A store will be automatically created if none is specified.
Other
Enables backward compatible conflicts postponing logic covering only conflicts between a task constraint and its incoming dependencies.
The project calendar.
Whether to include "As soon as possible" and "As late as possible" in the list of the constraints, for compatibility with the MS Project. Enabled by default.
Note, that when enabling this option, you can not have a regular constraint on the task and ASAP/ALAP flag in the same time.
See also docs of the direction field.
CRUD
Properties
94
Properties
94Advanced
Enables/disables the calculation progress notifications.
Experimental hook that lets the app determine if a bound dataset needs syncing with the store or not, and
if it does - which records that should be processed. Only called for stores that are configured with
syncDataOnLoad: true (which is the default in the React, Angular and Vue wrappers).
The main use case for this is for frameworks that update all state on any state change (like React), to not have to reapply the full bound dataset each time (which becomes costly).
If the app has a cheap way of determining (for example using a timestamp) that the dataset has no
changes, return false from this hook to prevent the store from syncing at all at that time.
shouldSyncDataOnLoad({ store, data }) {
if (store === myEventStore && timestamp <= lastUpdateTimestamp) {
// Prevent sync when the event store has not changed since last time
// (pseudocode)
return false;
}
}
If the app knows that something has changed, return a Set with ids for the records that should be
further processed by the sync logic.
shouldSyncDataOnLoad({ store, data }) {
if (store === myEventStore && timestamp > lastUpdateTimestamp) {
// Sync only these records (pseudocode)
return new Set([6, 110, 586]);
}
}
| Parameter | Type | Description |
|---|---|---|
options | Object | Options passed by the store to this hook |
options.store | Store | Store about to be synced |
options.records | Model | Records currently in the store |
options.data | Object[] | Incoming data |
Return false to prevent the store from syncing, or a set of
record ids that need further processing (for records that has some kind of change, eg. an update, removal
or addition)
State tracking manager instance the project relies on
Set to a IANA time zone (i.e. Europe/Stockholm) or a UTC offset in minutes (i.e. -120). This will
convert all events, tasks and time ranges to the specified time zone or offset. It will also affect the
displayed timeline's headers as well at the start and end date of it.
There is currently no built-in time zone support in JavaScript which means that the converted dates technically still are in the local system time zone, but adjusted to match the configured time zone.
DST
If a IANA time zone is provided, there will be support for DST. But if local system time zone has DST that will affect the time zone conversion at the exact hour when the local system time zone switches DST on and off.
For example:
- The local system time zone is
Europe/Stockholm(which is UTC+1 or UTC+2 when DST). - The date
2022-03-27T07:00:00Z(which is UTC) is converted toAmerica/Chicago(which is UTC-6 or UTC-5 when DST). - The converted JS date will be created from
2022-03-27T02:00:00which is exactly the hour whenEurope/Stockholmadds an DST hour. This has the effect that the converted date shows up incorrectly as2022-03-27T03:00instead.
If a UTC offset is provided, there is no DST support at all.
Editing
If creating new records or editing existing record dates, the dates will be interpreted as in the selected time zone.
If you want to create new records with dates that either should be interpreted as local system time zone or from any other time zone, specify the timeZone field on the record.
Saving
When saving or syncing data, the dates will be restored to local system time and converted to JSON
ISO formatted. When restoring, it adds or subtracts the time difference accordingly.
For instance, if the current timezone is UTC and you're in UTC +3, 3 hours will be added to the time.
The store.toJSON() and model.toJSON() methods also restores the data. For example, eventStore.toJSON()
will show the dates in local timezone.
Class hierarchy
Inline data
Get/set assignmentStore data.
Always returns an array of AssignmentModels but also accepts an array of its configuration objects as input.
Get/set calendarManagerStore data.
Always returns a CalendarModel array but also accepts an array of its configuration objects as input.
Get/set dependencyStore data.
Always returns an array of DependencyModels but also accepts an array of its configuration objects as input.
Get or set data of project stores. The returned data is identical to what toJSON returns:
const data = scheduler.project.inlineData;
// data:
{
tasks : [
{ id : 1, name : 'Proof-read docs', startDate : '2017-01-02', endDate : '2017-01-09' },
{ id : 2, name : 'Release docs', startDate : '2017-01-09', endDate : '2017-01-10' }
],
resources : [
{ id : 1, name : 'Arcady' },
{ id : 2, name : 'Don' }
],
dependencies : [
{ fromTask : 1, toTask : 2 }
],
assignments : [
{ 'event' : 1, 'resource' : 1 },
{ 'event' : 2, 'resource' : 2 }
]
}
// Plug it back in later
scheduler.project.inlineData = data;
xxData properties are deprecated and will be removed in the future. Use xx instead. For
example tasksData is deprecated, use tasks instead. For now, both naming schemes are included in
the data object
Get or set project data (records from its stores) as a JSON string.
Get a JSON string:
const project = new ProjectModel({
events : [...],
resources : [...],
assignments : [...],
dependencies : [...]
});
const jsonString = project.json;
// jsonString:
'{"events":[...],"resources":[...],...}'
Set a JSON string (to populate the project stores):
project.json = '{"events":[...],"resources":[...],...}'
xxData properties are deprecated and will be removed in the future. Use xx instead. For example
eventsData is deprecated, use events instead. For now, both naming schemes are included in the data object
Get/set resourceStore data.
Always returns an array of ResourceModels but also accepts an array of its configuration objects as input.
Get/set taskStore data.
Always returns an array of TaskModels but also accepts an array of its configuration objects as input.
Get/set timeRangeStore data.
Always returns an array of TimeSpans but also accepts an array of its configuration objects as input.
Legacy inline data
Whether to include legacy data properties in the JSON / inlineData output. The legacy data properties are
the xxData (eventsData, resourcesData etc.) properties that are deprecated and will be removed in
the future.
Models & Stores
The store holding the assignment information.
See also AssignmentModel
The store holding the calendar information.
See also CalendarModel
Returns current Project changes as an object consisting of added/modified/removed arrays of records for every
managed store. Returns null if no changes exist. Format:
{
resources : {
added : [{ name : 'New guy' }],
modified : [{ id : 2, name : 'Mike' }],
removed : [{ id : 3 }]
},
events : {
modified : [{ id : 12, name : 'Cool task' }]
},
...
}
The store holding the dependency information.
See also DependencyModel
The store holding the resources that can be assigned to the tasks in the task store.
See also ResourceModel
An alias for the eventStore.
See also TaskModel
Other
Class implementing a task segment. Can be used for customizing the class implementing segments:
// new class for a segment
class MySegment extends EventSegmentModel {
static fields = [
{ name : 'responsiblePerson' }
];
}
new Gantt({
project : {
// tell the project to use the new class for segments
segmentModelClass : MySegment
}
})
Scheduling
Returns an array of critical paths. Each critical path is an array of critical path nodes. Each critical path node is an object which contains critical task and dependency leading to the next critical path node. Dependency is missing if it is the last critical path node in the critical path. To highlight critical paths, enable CriticalPaths feature.
// This is an example of critical paths structure
[
// First path
[
{
event : Gantt.model.TaskModel
dependency : Gantt.model.DependencyModel
},
{
event : Gantt.model.TaskModel
}
],
// Second path
[
{
event : Gantt.model.TaskModel
}
]
// and so on....
]
For more details on the critical path method theory please check this article.
CRUD
Editing
Parent & children
Functions
77
Functions
77Advanced
Overrides the project owned store identifiers calculation and launches rescheduling.
| Parameter | Type | Description |
|---|---|---|
calculations | Object | Object providing new engine fields calculation function names. The object is grouped by store identifiers. For example below code overrides task startDate, endDate and duration calculation so the fields will always simply return their current values: |
Promise that resolves with an object having the overridden calculations. The object can be used to toggle the calculations back in the future:
// override event duration calculation
const oldCalculations = await project.setCalculations({
events : {
duration : "userProvidedValue"
}
})
// revert the duration calculation back
project.setCalculations(oldCalculations)
Inline data
Accepts a "data package" consisting of data for the projects stores, which is then loaded into the stores.
The package can hold data for TaskStore, AssignmentStore, ResourceStore, DependencyStore and Calendar Manager. It uses the same format as when creating a project with inline data:
await project.loadInlineData({
tasks : [
{ id : 1, name : 'Proof-read docs', startDate : '2017-01-02', endDate : '2017-01-09' },
{ id : 2, name : 'Release docs', startDate : '2017-01-09', endDate : '2017-01-10' }
],
resources : [
{ id : 1, name : 'Arcady' },
{ id : 2, name : 'Don' }
],
dependencies : [
{ fromTask : 1, toTask : 2 }
],
assignments : [
{ 'event' : 1, 'resource' : 1 },
{ 'event' : 2, 'resource' : 2 }
]
calendars : [
{
id : 111,
name : 'My cool calendar',
intervals : [
{
recurrentStartDate : 'on Sat',
recurrentEndDate : 'on Mon',
isWorking : false
}
]
}
]
});
xxData properties are deprecated and will be removed in the future. Use xx instead. For
example tasksData is deprecated, use tasks instead. For now, both naming schemes are included in
the data object
After populating the stores it commits the project, starting its calculations. By awaiting loadInlineData() you
can be sure that project calculations are finished.
| Parameter | Type | Description |
|---|---|---|
dataPackage | Object | A data package as described above |
Returns the data from the records of the projects stores, in a format that can be consumed by
loadInlineData().
Used by JSON.stringify to correctly convert this record to json.
The output format is determined by the value of toJSONResultFormat, as follows:
inlineData- Returns all crud store data, plus the project fields (under theprojectkey)model- Returns only the project fields
const project = new ProjectModel({
// Include both store data and project model fields in toJSON() result
toJSONResultFormat : 'inlineData',
events : [...],
resources : [...],
assignments : [...],
dependencies : [...],
resourceTimeRanges : [...],
timeRanges : [...]
});
const json = project.toJSON();
// json:
{
events : [...],
resources : [...],
assignments : [...],
dependencies : [...],
...
project : {
addConstraintOnDateSet : false,
daysPerMonth : 13
daysPerWeek : 3
...
},
...
}
xxData properties are deprecated and will be removed in the future. Use xx instead. For
example eventsData is deprecated, use events instead. For now, both naming schemes are included in
the data object
Output can be consumed by loadInlineData():
const json = project.toJSON();
// Plug it back in later
project.loadInlineData(json);
Other
Defines if the given project field should be manually editable in UI. You can override this method to provide your own logic.
| Parameter | Type | Description |
|---|---|---|
fieldName | String | Name of the field |
Returns true if the field is editable, false if it is not and undefined if the task has
no such field.
Sets the project start date and commits the changes.
| Parameter | Type | Description |
|---|---|---|
date | Date | The new start date to set |
keepDuration | Boolean | Whether the intention is to keep the |
Scheduling
Project changes (CRUD operations to records in its stores) are automatically committed on a buffer to the underlying graph based calculation engine. The engine performs it calculations async.
By calling this function, the commit happens right away. And by awaiting it you are sure that project calculations are finished and that references between records are up to date.
The returned promise is resolved with an object. If that object has rejectedWith set, there has been a conflict and the calculation failed.
// Move a task in time
taskStore.first.shift(1);
// Trigger calculations directly and wait for them to finish
const result = await project.commitAsync();
if (result.rejectedWith) {
// there was a conflict during the scheduling
}
Returns a calendar of the project. If task has never been assigned a calendar a project's calendar will be returned.
Causes the scheduling engine to re-evaluate the task data and all associated data and constraints and apply necessary changes.
Resume propagation. If propagation is resumed (calls may be nested which increments a suspension counter), then if a call to propagate was made during suspension, propagate is executed.
| Parameter | Type | Description |
|---|---|---|
trigger | Boolean | Pass |
Sets the calendar of the project. Will cause the schedule to be updated - returns a Promise
| Parameter | Type | Description |
|---|---|---|
calendar | CalendarModel | The new calendar. |
Suspend propagation processing. When propagation is suspended, calls to propagate do not proceed, instead a propagate call is deferred until a matching resumePropagate is called.
Configuration
CRUD
Editing
Events
JSON
Parent & children
Revisions
Events
10
Events
10Fired when data in any of the projects stores changes.
Basically a relayed version of each stores own change event, decorated with which store it originates from. See the store change event documentation for more information.
// Adding a listener using the "on" method
projectModel.on('change', ({ source, store, action, record, records, changes }) => {
});| Parameter | Type | Description |
|---|---|---|
source | ProjectModel | This project |
store | Store | Affected store |
action | remove | removeAll | add | clearchanges | filter | update | dataset | replace | Name of action which triggered the change. May be one of the options listed above. |
record | Model | Changed record, for actions that affects exactly one record ( |
records | Model[] | Changed records, passed for all actions except |
changes | Object | Passed for the |
Fired when the Engine detects a computation cycle.
// Adding a listener using the "on" method
projectModel.on('cycle', ({ schedulingIssue, schedulingIssue.getDescription, schedulingIssue.cycle, schedulingIssue.getResolutions, continueWithResolutionResult }) => {
});| Parameter | Type | Description |
|---|---|---|
schedulingIssue | Object | Scheduling error describing the case: |
schedulingIssue.getDescription | function | Returns the cycle description |
schedulingIssue.cycle | Object | Object providing the cycle info |
schedulingIssue.getResolutions | function | Returns possible resolutions |
continueWithResolutionResult | function | Function to call after a resolution is chosen to proceed with the Engine calculations:
Where |
Fired when the engine has finished its calculations and the results has been written back to the records.
gantt.project.on({
dataReady({ records }) {
console.log('Calculations finished');
for (const record of records) {
console.log(`Modified #${record.id}: ${JSON.stringify(record.modifications)}`);
}
// Output:
// Modified #12: {"endDate":null,"duration":7200000,"id":12}
// Modified #1: {"percentDone":49.99998611112847,"id":1}
// Modified #1000: {"percentDone":49.99965834045124,"id":1000}
}
});
gantt.project.taskStore.first.duration = 10;
// At some point a bit later it will log 'Calculations finished', etc.
// Adding a listener using the "on" method
projectModel.on('dataReady', ({ source, isInitialCommit, records }) => {
});| Parameter | Type | Description |
|---|---|---|
source | ProjectModel | The project |
isInitialCommit | Boolean | Flag that shows if this commit is initial |
records | Set | Set of all Models that were modified in the completed transaction. Use the modifications property of each Model to identify modified fields. |
Fired when the Engine detects a calendar misconfiguration when the calendar does not provide any working periods of time which makes usage impossible.
// Adding a listener using the "on" method
projectModel.on('emptyCalendar', ({ schedulingIssue, schedulingIssue.getDescription, schedulingIssue.getCalendar, schedulingIssue.getResolutions, continueWithResolutionResult }) => {
});| Parameter | Type | Description |
|---|---|---|
schedulingIssue | Object | Scheduling error describing the case: |
schedulingIssue.getDescription | function | Returns the error description |
schedulingIssue.getCalendar | function | Returns the calendar that must be fixed |
schedulingIssue.getResolutions | function | Returns possible resolutions |
continueWithResolutionResult | function | Function to call after a resolution is chosen to proceed with the Engine calculations: |
Fired during the Engine calculation if enableProgressNotifications config is true
// Adding a listener using the "on" method
projectModel.on('progress', ({ source, total, remaining, phase }) => {
});| Parameter | Type | Description |
|---|---|---|
source | ProjectModel | The owning project |
total | Number | The total number of operations |
remaining | Number | The number of remaining operations |
phase | storePopulation | propagating | The phase of the calculation, either 'storePopulation' when data is getting loaded, or 'propagating' when data is getting calculated |
Fired when the Engine detects a scheduling conflict.
// Adding a listener using the "on" method
projectModel.on('schedulingConflict', ({ schedulingIssue, schedulingIssue.getDescription, schedulingIssue.intervals, schedulingIssue.getResolutions, continueWithResolutionResult }) => {
});| Parameter | Type | Description |
|---|---|---|
schedulingIssue | Object | The conflict details: |
schedulingIssue.getDescription | function | Returns the conflict description |
schedulingIssue.intervals | Object[] | Array of conflicting intervals |
schedulingIssue.getResolutions | function | Function to get possible resolutions |
continueWithResolutionResult | function | Function to call after a resolution is chosen to proceed with the Engine calculations:
Where |
Event handlers
10
Event handlers
10Called when data in any of the projects stores changes.
Basically a relayed version of each stores own change event, decorated with which store it originates from. See the store change event documentation for more information.
new ProjectModel({
onChange({ source, store, action, record, records, changes }) {
}
});| Parameter | Type | Description |
|---|---|---|
source | ProjectModel | This project |
store | Store | Affected store |
action | remove | removeAll | add | clearchanges | filter | update | dataset | replace | Name of action which triggered the change. May be one of the options listed above. |
record | Model | Changed record, for actions that affects exactly one record ( |
records | Model[] | Changed records, passed for all actions except |
changes | Object | Passed for the |
Called when the Engine detects a computation cycle.
new ProjectModel({
onCycle({ schedulingIssue, continueWithResolutionResult }) {
}
});| Parameter | Type | Description |
|---|---|---|
schedulingIssue | Object | Scheduling error describing the case: |
schedulingIssue.getDescription | function | Returns the cycle description |
schedulingIssue.cycle | Object | Object providing the cycle info |
schedulingIssue.getResolutions | function | Returns possible resolutions |
continueWithResolutionResult | function | Function to call after a resolution is chosen to proceed with the Engine calculations:
Where |
Called when the engine has finished its calculations and the results has been written back to the records.
gantt.project.on({
dataReady({ records }) {
console.log('Calculations finished');
for (const record of records) {
console.log(`Modified #${record.id}: ${JSON.stringify(record.modifications)}`);
}
// Output:
// Modified #12: {"endDate":null,"duration":7200000,"id":12}
// Modified #1: {"percentDone":49.99998611112847,"id":1}
// Modified #1000: {"percentDone":49.99965834045124,"id":1000}
}
});
gantt.project.taskStore.first.duration = 10;
// At some point a bit later it will log 'Calculations finished', etc.
new ProjectModel({
onDataReady({ source, isInitialCommit, records }) {
}
});| Parameter | Type | Description |
|---|---|---|
source | ProjectModel | The project |
isInitialCommit | Boolean | Flag that shows if this commit is initial |
records | Set | Set of all Models that were modified in the completed transaction. Use the modifications property of each Model to identify modified fields. |
Called when the Engine detects a calendar misconfiguration when the calendar does not provide any working periods of time which makes usage impossible.
new ProjectModel({
onEmptyCalendar({ schedulingIssue, continueWithResolutionResult }) {
}
});| Parameter | Type | Description |
|---|---|---|
schedulingIssue | Object | Scheduling error describing the case: |
schedulingIssue.getDescription | function | Returns the error description |
schedulingIssue.getCalendar | function | Returns the calendar that must be fixed |
schedulingIssue.getResolutions | function | Returns possible resolutions |
continueWithResolutionResult | function | Function to call after a resolution is chosen to proceed with the Engine calculations: |
Called during the Engine calculation if enableProgressNotifications config is true
new ProjectModel({
onProgress({ source, total, remaining, phase }) {
}
});| Parameter | Type | Description |
|---|---|---|
source | ProjectModel | The owning project |
total | Number | The total number of operations |
remaining | Number | The number of remaining operations |
phase | storePopulation | propagating | The phase of the calculation, either 'storePopulation' when data is getting loaded, or 'propagating' when data is getting calculated |
Called when the Engine detects a scheduling conflict.
new ProjectModel({
onSchedulingConflict({ schedulingIssue, continueWithResolutionResult }) {
}
});| Parameter | Type | Description |
|---|---|---|
schedulingIssue | Object | The conflict details: |
schedulingIssue.getDescription | function | Returns the conflict description |
schedulingIssue.intervals | Object[] | Array of conflicting intervals |
schedulingIssue.getResolutions | function | Function to get possible resolutions |
continueWithResolutionResult | function | Function to call after a resolution is chosen to proceed with the Engine calculations:
Where |
Typedefs
3
Typedefs
3Fields
23
Fields
23If this flag is set to true (default) when a start/end date is set on the event, a corresponding
start-no-earlier/later-than constraint is added, automatically. This is done in order to
keep the event "attached" to this date, according to the user intention.
Depending on your use case, you might want to disable this behaviour.
If this field is set to true scheduling conflicts
will include an additional resolution option to "postpone" the conflict resolution.
The conflict then is stored in the task
postponedConflict field
and can be visualized with the TaskInfoColumn.
To force the resolution of such conflict programmatically, one should call the resolvePostponedConflict method.
true to enable automatic % done calculation for summary
tasks, false to disable it.
When true (default) adjacent or overlapping task segments get merged automatically.
If this field is set to true scheduling conflicts
will not show the conflict resolution popup but instead will be saved into
tasks postponedConflict field.
See also the docs for allowPostponedConflicts for additional details.
If this field is set to true scheduling conflicts
will not show the conflict resolution popup but instead will be saved into
tasks postponedConflict field.
When this flag is enabled (default), manually scheduled tasks are scheduled automatically on the 2nd scheduling pass. This is a backward pass ("late" start/end dates) for forward-scheduled project and forward pass ("early" start/end dates) for backward-scheduled project. Because of it, manually scheduled tasks may have non-zero slack.
This is the same behaviour as in MSProject, though you might have different requirements.
When this flag is disabled, manually scheduled tasks are "fixed" in time during both passes, so they will always have 0 slack.
The project calendar.
The number of days per month.
Please note: the value does not define the amount of working time per month for that purpose one should use calendars.
The value is used when converting the duration from one unit to another.
So when user enters a duration of, for example, 1 month the system understands that it
actually means 30 days (which is then converted to hours) and
schedules accordingly.
The number of days per week.
Please note: the value does not define the amount of working time per week for that purpose one should use calendars.
The value is used when converting the duration from one unit to another.
So when user enters a duration of, for example, 2 weeks the system understands that it
actually means 14 days (which is then converted to hours) and
schedules accordingly.
The source of the calendar for dependencies (the calendar used for taking dependencies lag into account). Possible values are:
ToEvent- successor calendar will be used (default);FromEvent- predecessor calendar will be used;Project- the project calendar will be used.AllWorking- the project 24/7 elapsed calendar will be used.
Description of the project
The scheduling direction of the project tasks.
The Forward direction corresponds to the As-Soon-As-Possible (ASAP) scheduling,
Backward - to As-Late-As-Possible (ALAP).
To set the scheduling direction of the individual tasks, use the direction field of the TaskModel.
End date of the project in the ISO 8601 format. The value is calculated as the latest date among all tasks.
Note that the field always returns a Date.
The number of hours per day.
Please note: the value does not define the amount of working time per day for that purpose one should use calendars.
The value is used when converting the duration from one unit to another.
So when user enters a duration of, for example, 5 days the system understands that it
actually means 120 hours and schedules accordingly.
This option is experimental and subject for possible change.
The second scheduling pass is a backward pass ("late" start/end dates) for forward-scheduled project and forward pass ("early" start/end dates) for backward-scheduled project.
When this flag is enabled, if a conflict between the task's constraint and incoming dependencies occurs during the 2nd scheduling pass, the task's constraint is ignored and task is scheduled according to its dependencies.
This happens only during the specified type of conflict. For other types of conflict and for no-conflict case scheduling is performed as usual.
Enabling this option will enable tasks to have negative slack, which sometimes is desirable.
The maximum number of critical paths to collect in criticalPaths. When critical tasks connectivity is high (there are many of such tasks having many critical predecessors) the tasks might produce a huge number of critical paths which can't really be handled by a browser. So this value limits the number of paths to collect to protect from such cases.
Set the value to zero to disable the limitation.
Name of the project
When true the project's manually scheduled tasks duration will include only working periods of time.
When false such tasks will ignore working time calendars and treat all intervals as working.
IMPORTANT: Setting this to false also forcefully sets the
skipNonWorkingTimeWhenSchedulingManually option to false.
When true the project manually scheduled tasks will adjust their proposed start/end dates
to skip non working time.
Start date of the project in the ISO 8601 format. Setting this date will constrain all other tasks in the project to start no earlier than it.
If this date is not provided, it will be calculated as the earliest date among all tasks.
Note that the field always returns a Date.
Specifies how started tasks are scheduled. Possible values are:
Auto- (default) tasks are scheduled regardless of whether they are started or notManual- started tasks preserve their current positions ignoring their dependencies The rationale behind this is a started task implies its start date is already established and thus should not be calculated dynamically.
The status date of the project. It is just a date, that sets a reference point to various reporting facilities, like ProgressLine or PlannedPercentDoneColumn.
By default, the current date/time is used.