NestedEvents
A feature that renders child events nested inside their parent. Requires Scheduler Pro to use a tree event store (normally handled automatically when events in data has children).
//<code-header>
fiddle.title = 'Nested events';
//</code-header>
const schedulerPro = new SchedulerPro({
appendTo : targetElement,
// makes scheduler as high as it needs to be to fit rows
autoHeight : true,
features : {
nestedEvents : true
},
rowHeight : 160,
startDate : new Date(2022, 2, 20),
endDate : new Date(2022, 2, 27),
columns : [
{ field : 'name', text : 'Name', width : 100 }
],
project : {
resources : [
{ id : 1, name : 'Bruce' },
{ id : 2, name : 'Diana' }
],
events : [
{
id : 1,
name : 'Art project',
startDate : '2022-03-21',
duration : 5,
children : [
{ id : 11, name : 'Get supplies', startDate : '2022-03-21', duration : 2 },
{ id : 12, name : 'Sketch', startDate : '2022-03-22', duration : 1, eventColor : 'indigo' },
{ id : 13, name : 'Outline', startDate : '2022-03-22', duration : 2, eventColor : 'blue' },
{ id : 14, name : 'Ink', startDate : '2022-03-23', duration : 2, eventColor : 'violet' },
{ id : 15, name : 'Share', startDate : '2022-03-24', duration : 2, eventColor : 'pink' }
]
},
{
id : 2,
name : 'DIY project',
startDate : '2022-03-24',
duration : 5,
children : [
{ id : 21, name : 'Plan', startDate : '2022-03-21', duration : 1, eventColor : 'indigo' },
{ id : 22, name : 'Get supplies', startDate : '2022-03-22', duration : 2 },
{ id : 23, name : 'Prototype', startDate : '2022-03-22', duration : 3, eventColor : 'violet' },
{ id : 24, name : 'Make', startDate : '2022-03-24', duration : 1, eventColor : 'blue' }
]
}
],
assignments : [
{ id : 1, event : 1, resource : 1 },
{ id : 2, event : 11, resource : 1 },
{ id : 3, event : 12, resource : 1 },
{ id : 4, event : 13, resource : 1 },
{ id : 5, event : 14, resource : 1 },
{ id : 6, event : 15, resource : 1 },
{ id : 7, event : 2, resource : 2 },
{ id : 8, event : 21, resource : 2 },
{ id : 9, event : 22, resource : 2 },
{ id : 10, event : 23, resource : 2 },
{ id : 11, event : 24, resource : 2 }
]
},
tbar : [
{
type : 'buttongroup',
toggleGroup : true,
rendition : 'padded',
items : {
none : { text : 'Overlap' },
stack : { text : 'Stack' },
pack : { text : 'Pack', pressed : true }
},
onToggle({ source, pressed }) {
if (pressed) {
schedulerPro.features.nestedEvents.eventLayout = source.ref;
}
}
}
]
});The feature has configs for eventLayout, resourceMargin and barMargin that are separate from those on Scheduler Pro and only affect nested events.
You can by default drag nested events out of their parents and drop any event onto root level events to nest. The drag and drop behaviour can be customized using the constrainDragToParent, allowNestingOnDrop and allowDeNestingOnDrop configs.
Parent / children scheduling
Scheduler Pro uses a scheduling engine closely related to the one used by Gantt (a subset of it). It for example schedules based on calendars (skipping non-working time), dependencies and constraints.
Scheduling parents
Part of the scheduling engines default logic is that parent events' start and end dates (and thus duration) is defined by their children. This means that if you remove the latest scheduled child of a parent, the parents end date and duration will be adjusted to match the new latest scheduled child (shrink-wrapping children).
Depending on what you plan to use nested events for in your application, this might not be the desired behaviour. If you want the parent event to keep its dates regardless of its children, you should flag it as manuallyScheduled.
A parent defined like this will shrink / grow with its children:
{
"id" : 1,
"startDate" : "2022-03-24",
"children" : [
...
]
}
Try removing an event here to see what happens:
//<code-header>
fiddle.title = 'Nested events not manually';
//</code-header>
const schedulerPro = new SchedulerPro({
appendTo : targetElement,
// makes scheduler as high as it needs to be to fit rows
autoHeight : true,
features : {
nestedEvents : true
},
rowHeight : 80,
startDate : new Date(2022, 2, 20),
endDate : new Date(2022, 2, 27),
columns : [
{ field : 'name', text : 'Name', width : 100 }
],
project : {
resources : [
{ id : 1, name : 'Dude' }
],
events : [
{
id : 1,
name : 'Automatically scheduled',
startDate : '2022-03-21',
children : [
{ id : 11, name : 'Start here', startDate : '2022-03-21', duration : 2 },
{ id : 12, name : 'End here', startDate : '2022-03-24', duration : 2, eventColor : 'orange' }
]
}
],
assignments : [
{ id : 1, event : 1, resource : 1 },
{ id : 2, event : 11, resource : 1 },
{ id : 3, event : 12, resource : 1 }
]
}
});A parent with manuallyScheduled : true will not shrink / grow with is children:
{
"id" : 1,
"startDate" : "2022-03-24",
"duration" : 10,
"manuallyScheduled" : true
"children" : [
...
]
}
Try the same thing here:
//<code-header>
fiddle.title = 'Nested events manually';
//</code-header>
const schedulerPro = new SchedulerPro({
appendTo : targetElement,
// makes scheduler as high as it needs to be to fit rows
autoHeight : true,
features : {
nestedEvents : true
},
rowHeight : 80,
startDate : new Date(2022, 2, 20),
endDate : new Date(2022, 2, 27),
columns : [
{ field : 'name', text : 'Name', width : 100 }
],
project : {
resources : [
{ id : 1, name : 'Guy' }
],
events : [
{
id : 1,
name : 'Manually scheduled',
startDate : '2022-03-21',
duration : 5,
manuallyScheduled : true,
children : [
{ id : 11, name : 'Start here?', startDate : '2022-03-21', duration : 2 },
{ id : 12, name : 'End here?', startDate : '2022-03-24', duration : 2, eventColor : 'orange' }
]
}
],
assignments : [
{ id : 1, event : 1, resource : 1 },
{ id : 2, event : 11, resource : 1 },
{ id : 3, event : 12, resource : 1 }
]
}
});manuallyScheduled: trueDrag and drop for parent events
Normally the dates of a parent event is defined by its children (as described above), with exception for when drag dropping a parent event along the time axis. In this case the operation will update the dates of all the children, which will thus also move the parent event in time.
If a parent event is dragged to a new resource, all its children will also be assigned to that resource.
Scheduling children (nested events)
Nested events are scheduled using much of the same logic as normal/parent events, but with some differences:
-
To maintain the relative position in time of nested events within their parent, they utilize a
delayFromParentfield. The field accepts a magnitude ofdurationUnit(defaults to days). Sample dataset (note that supplyingdelayFromParentis optional, see the next bullet):{ "name" : "Parent", "startDate" : "2023-08-21", // Monday "children" : [ { "name" : "Child 1", "delayFromParent" : 0 } { "name" : "Child 2", "delayFromParent" : 2 } ] }Parent starts on 2023-08-21, the first child will start on the same date, the second child will start 2 days later (2023-08-23).
If the parent instead started on a Friday, the outcome would be that the second child starts 2 working days later, which would be the following Tuesday.
Note that when supplying
delayFromParentin data, since parent events shrink wrap their children, the earliest child must have"delayFromParent": 0. -
If
delayFromParentis not present in the loaded data, the field is calculated asnestedStart - parentStart - non-working time(for example if parent starts on a Friday, and nested event on a Monday,delayFromParentwill be 1). Sample dataset:{ "name" : "Parent", "startDate" : "2023-08-21", // Monday "children" : [ { "name" : "Child 1", "startDate" : "2023-08-21" }, { "name" : "Child 2", "startDate" : "2023-08-23" } ] }Yields the same result as above, parent and first child starts on 2023-08-21, second child starts 2 days later. Child 1 gets
delayFromParent: 0and child 2 getsdelayFromParent: 2from the calculation.
Dependencies
Nested events support dependencies, with some caveats:
- Dependency lines are by default drawn on the top of events, instead of behind them. This is to ensure they are
visible when drawn into a parent (or fully within one). The Dependencies feature can be configured with
drawAroundParents set to
trueto instead attempt to draw around parents when possible. - When using dependencies, the body of parent events with overflowing nested children is not scrollable. This is
because there is no tracking of the scrolling of parent events, and thus dependency lines would not be drawn
correctly on scroll. If your app only needs dependencies between parents, you can configure allowCreateOnlyParent
as
true. In this case, their container is scrollable. - Dependencies are only supported for one level of nesting (with
maxNesting: 1, which is the default).
//<code-header>
fiddle.title = 'Nested events dependencies';
//</code-header>
const schedulerPro = new SchedulerPro({
appendTo : targetElement,
autoHeight : true,
features : {
nestedEvents : true,
dependencies : {
terminalOffset : 8
}
},
rowHeight : 90,
startDate : new Date(2022, 2, 20),
endDate : new Date(2022, 2, 27),
project : {
resources : [
{ id : 1, name : 'Bruce' }
],
events : [
{
id : 1,
name : 'Art project',
startDate : '2022-03-21',
duration : 5,
children : [
{ id : 11, name : 'Supplies', delayFromParent : 0, duration : 1 },
{ id : 12, name : 'Sketch', delayFromParent : 1, duration : 1, eventColor : 'indigo' },
{ id : 13, name : 'Outline', delayFromParent : 2, duration : 1, eventColor : 'blue' }
]
}
],
assignments : [
{ id : 1, event : 1, resource : 1 },
{ id : 2, event : 11, resource : 1 },
{ id : 3, event : 12, resource : 1 },
{ id : 4, event : 13, resource : 1 }
],
dependencies : [
{ id : 1, from : 11, to : 12, lag : 1 },
{ id : 2, from : 12, to : 13, lag : 0.5 }
]
}
});Caveats
Usage of the feature comes with some requirements/caveats:
- As already mentioned, it requires a tree event store
- Requires using an AssignmentStore, the legacy single assignment mode does not handle tree stores
- Scheduler must use stack or overlap eventLayout, pack not supported
- Multi event drag is not supported for nested events
- Cannot EventDragCreate within parent events
- Labels are not supported for nested events
- EventBuffer won't work with nested events
- TaskEdit does not allow assigning resources or dependencies to nested events
- Does not work in combination with recurring events
This feature is disabled by default. For info on enabling it, see GridFeatures.
Configs
19
Configs
19Other
Allow dropping a nested event directly on a resource to de-nest it, turning it into an ordinary event.
Requires constrainDragToParent to be configured with false to be applicable.
Allow an event to be dropped on another to nest it.
Dropping an event on another will add the dropped event as a child of the target, turning the target into a parent if it was not already.
Parent events dropped on another event are ignored.
Vertical (horizontal in vertical mode) space between nested event bars, in px
Constrains dragging of nested events within their parent when configured as true, allows them to be
dragged out of it when configured as false (the default).
Constrains resizing of nested events to their parents start and end dates when configured as true (the
default), preventing them from changing their parents dates.
Configure as false if you want to allow resizing operations to extend the parents dates (only applies for
parents not configured with manuallyScheduled: true).
Fixed event height (width in vertical mode) to use when configured with eventLayout : 'stack'.
Also accepts an array, used to control height for each level if nesting deeper than 1 level. Make sure you supply a value for each level, where later values are smaller than earlier ones.
const scheduler = new SchedulerPro({
features : {
nestedEvents : {
eventHeight : [40, 20]
}
});
This config defines how to handle overlapping nested events. Valid values are:
stack, events use fixed height and stack on top of each other (not supported in vertical mode)pack, adjusts event heightnone, allows events to overlap
Space (in px) in a parent element reserved for displaying a title etc. Used to compute available space for the nested events container inside the parent.
Setting this config updates the --b-nested-events-header-height CSS variable.
Maximum nesting level for events.
Larger depths than 2 are not recommended, even if technically possible.
Scheduled events
Control how much space to leave between the first nested event bar/last nested event and the parent event (top/bottom margin within the parent event row in horizontal mode, left/right margin within the parent event column in vertical mode), in px.
It's also possible to set different values for top/left and bottom/right
by assigning an object to resourceMargin with start (margin top in horizontal mode,
margin left in vertical mode) and end (margin bottom / margin right) properties:
scheduler = new SchedulerPro({
features : {
nestedEvents : {
resourceMargin : {
start : 15,
end : 1
}
}
}
});
Misc
Properties
25
Properties
25Common
Class hierarchy
Other
Allow dropping a nested event directly on a resource to de-nest it, turning it into an ordinary event.
Requires constrainDragToParent to be configured with false to be applicable.
Allow an event to be dropped on another to nest it.
Dropping an event on another will add the dropped event as a child of the target, turning the target into a parent if it was not already.
Parent events dropped on another event are ignored.
Vertical (horizontal in vertical mode) space between nested event bars, in px
Constrains dragging of nested events within their parent when configured as true, allows them to be
dragged out of it when configured as false (the default).
Constrains resizing of nested events to their parents start and end dates when configured as true (the
default), preventing them from changing their parents dates.
Configure as false if you want to allow resizing operations to extend the parents dates (only applies for
parents not configured with manuallyScheduled: true).
Fixed event height (width in vertical mode) to use when configured with eventLayout : 'stack'.
Also accepts an array, used to control height for each level if nesting deeper than 1 level. Make sure you supply a value for each level, where later values are smaller than earlier ones.
const scheduler = new SchedulerPro({
features : {
nestedEvents : {
eventHeight : [40, 20]
}
});
This config defines how to handle overlapping nested events. Valid values are:
stack, events use fixed height and stack on top of each other (not supported in vertical mode)pack, adjusts event heightnone, allows events to overlap
Space (in px) in a parent element reserved for displaying a title etc. Used to compute available space for the nested events container inside the parent.
Setting this config updates the --b-nested-events-header-height CSS variable.
Maximum nesting level for events.
Larger depths than 2 are not recommended, even if technically possible.
Scheduled events
Control how much space to leave between the first nested event bar/last nested event and the parent event (top/bottom margin within the parent event row in horizontal mode, left/right margin within the parent event column in vertical mode), in px.
It's also possible to set different values for top/left and bottom/right
by assigning an object to resourceMargin with start (margin top in horizontal mode,
margin left in vertical mode) and end (margin bottom / margin right) properties:
scheduler = new SchedulerPro({
features : {
nestedEvents : {
resourceMargin : {
start : 15,
end : 1
}
}
}
});
Functions
28
Functions
28Configuration
Events
Misc
Other
Events
5
Events
5Event handlers
5
Event handlers
5Typedefs
1
Typedefs
1CSS variables
8
CSS variables
8| Name | Description |
|---|---|
--b-nested-events-header-height | Parent event header height, to display the name at top |
--b-nested-events-parent-color | Parent event color |
--b-nested-events-parent-background | Parent event background |
--b-nested-events-container-background | Nested event container background (below the header in a parent event) |
| Hovered | |
--b-nested-events-parent-hover-background | Parent event hover background |
--b-nested-events-container-hover-background | Nested event container hover background |
| Selected | |
--b-nested-events-parent-selected-background | Parent event selected background |
--b-nested-events-container-selected-background | Nested event container selected background |