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).

Nested events
//<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.

Note that for a nested event to show up for a resource both the parent and the nested event has to be assigned to that resource.

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.

Note that by flagging an event as manually scheduled, it will no longer take non-working time or constraints into account either.

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:

Nested events not manually
//<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:

Nested events manually
//<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 }
        ]
    }
});

Note that this also makes resizing a parent event that is not manually scheduled useless, it would only snap back to the dates defined by its children. To avoid confusion, resizing is turned off for parent events unless they have manuallyScheduled: true

Drag 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 delayFromParent field. The field accepts a magnitude of durationUnit (defaults to days). Sample dataset (note that supplying delayFromParent is 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 delayFromParent in data, since parent events shrink wrap their children, the earliest child must have "delayFromParent": 0.

  • If delayFromParent is not present in the loaded data, the field is calculated as nestedStart - parentStart - non-working time (for example if parent starts on a Friday, and nested event on a Monday, delayFromParent will 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: 0 and child 2 gets delayFromParent: 2 from 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 true to 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).

Nested events dependencies
//<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

Common

disabledInstancePlugin
listenersEvents

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).

Note that when using `eventLayout: stack` the nested events are clipped by the parent, the part extending outside if not constrained to parent will not be shown until it re-renders after resize. If stacking events in your app won't overflow the parent, you can specify `overflow: visible` on `.b-nested-events-container.b-nested-events-layout-stack` to not clip.
eventHeight: Number | Number[]= 30Also a property

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]
    }
});
eventLayout: stack | pack | none= packAlso a property

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 height
  • none, allows events to overlap
Note that stacking works differently for nested events as compared to normal events (and not at all in vertical mode). The height of the parent event will never change, all nested events use fixed height and will stack until all available space is consumed, after which they will overflow the parent.
Also note that stacked nested events are clipped by the parent, making it scrollable on vertical overflow. This cannot be combined with sticky events. If stacking events in your app won't overflow the parent, you can specify `overflow: visible` on `.b-nested-events-container.b-nested-events-layout-stack` to not clip and make sticky events work.

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

clientInstancePlugin
localeClassLocalizable
localizableLocalizable

Properties

25

Common

disabledInstancePlugin

Class hierarchy

isNestedEvents: Boolean= truereadonly
Identifies an object as an instance of NestedEvents class, or subclass thereof.
isNestedEvents: Boolean= truereadonlystatic
Identifies an object as an instance of NestedEvents class, or subclass thereof.
isEventsEvents
isInstancePluginInstancePlugin
isLocalizableLocalizable

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).

Note that when using `eventLayout: stack` the nested events are clipped by the parent, the part extending outside if not constrained to parent will not be shown until it re-renders after resize. If stacking events in your app won't overflow the parent, you can specify `overflow: visible` on `.b-nested-events-container.b-nested-events-layout-stack` to not clip.
eventHeight: Number | Number[]= 30Also a config

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]
    }
});
eventLayout: stack | pack | none= packAlso a config

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 height
  • none, allows events to overlap
Note that stacking works differently for nested events as compared to normal events (and not at all in vertical mode). The height of the parent event will never change, all nested events use fixed height and will stack until all available space is consumed, after which they will overflow the parent.
Also note that stacked nested events are clipped by the parent, making it scrollable on vertical overflow. This cannot be combined with sticky events. If stacking events in your app won't overflow the parent, you can specify `overflow: visible` on `.b-nested-events-container.b-nested-events-layout-stack` to not clip and make sticky events work.

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
            }
        }
    }
});

Lifecycle

configBase

Misc

clientInstancePlugin
localeHelperLocalizable
localeManagerLocalizable

Functions

28

Configuration

applyDefaultsstaticBase

Events

Lifecycle

destroystaticBase

Misc

doDisableInstancePlugin
initClassstaticBase
isOfTypeNamestaticBase
mixinstaticBase
optionalLstaticLocalizable

Other

LstaticLocalizable
onEvents
relayAllEvents
triggerEvents
unEvents

Events

5
catchAllEvents
destroyEvents
disableInstancePlugin
enableInstancePlugin

Event handlers

5
onDestroyEvents
onDisableInstancePlugin
onEnableInstancePlugin

Typedefs

1

CSS variables

8
NameDescription
--b-nested-events-header-heightParent event header height, to display the name at top
--b-nested-events-parent-colorParent event color
--b-nested-events-parent-backgroundParent event background
--b-nested-events-container-backgroundNested event container background (below the header in a parent event)
Hovered
--b-nested-events-parent-hover-backgroundParent event hover background
--b-nested-events-container-hover-backgroundNested event container hover background
Selected
--b-nested-events-parent-selected-backgroundParent event selected background
--b-nested-events-container-selected-backgroundNested event container selected background