TreeGroup

A feature that allows transforming a flat dataset (or the leaves of a hierarchical) into a tree by specifying a record field per parent level. Parents are generated based on each leaf's value for those fields.

Tree group
//<code-header>
fiddle.title = 'Tree group';
//</code-header>
const grid = new TreeGrid({
    appendTo : targetElement,

    // Makes grid as high as it needs to be to fit rows
    autoHeight : true,

    // Initial dataset, will be transformed by the TreeGroup feature
    store : {
        fields : [
            'name',
            'status',
            'prio'
        ],
        data : [
            {
                id       : 1,
                name     : 'Project 1',
                expanded : true,
                children : [
                    { id : 11, name : 'Task 11', status : 'WIP', prio : 'High' },
                    { id : 12, name : 'Task 12', status : 'Done', prio : 'Low' },
                    { id : 13, name : 'Task 13', status : 'Done', prio : 'High' }
                ]
            },
            {
                id       : 2,
                name     : 'Project 2',
                expanded : true,
                children : [
                    { id : 21, name : 'Task 21', status : 'WIP', prio : 'High' }
                ]
            }
        ]
    },

    columns : [
        { type : 'tree', field : 'name', text : 'Name', flex : 1 }
    ],

    features : {
        treeGroup : {
            levels : ['status'],
            // Customize the cell / row element or the value displayed using parentRenderer
            parentRenderer({ value, cellElement, row, grid }) {
                const cls = value === 'Done' ? 'check-circle' : 'clock';
                return `<i class="fa fa-${cls}" style="margin-inline-end:.5em;color:${cls === 'check-circle' ? 'green' : 'lightgray'}"></i>${value}`;
            }
        }
    },

    tbar : [
        {
            type        : 'buttongroup',
            toggleGroup : true,
            items       : [
                {
                    text    : 'Status',
                    pressed : true,
                    onToggle({ pressed }) {
                        pressed && grid.group(['status']);
                    }
                },
                {
                    text : 'Prio',
                    onToggle({ pressed }) {
                        pressed && grid.group(['prio']);
                    }
                },
                {
                    text : 'Status + Prio',
                    onToggle({ pressed }) {
                        pressed && grid.group(['status', 'prio']);
                    }
                },
                {
                    text : 'none',
                    onToggle({ pressed }) {
                        pressed && grid.clearGroups();
                    }
                }
            ]
        }
    ]
});

This feature can be used to mimic multi grouping or to generate another view for hierarchical data. The actual transformation happens in a new store, that contains links to the original records. The original store's structure is kept intact and will be plugged back in when calling clearGroups. When grouping on a column field, the column´s format method will be used to format the value to group by (relevant for NumberColumn, DateColumn etc.)

Any modification of the links is relayed to the original store. So cell editing and other features will work as expected and the original data will be updated.

Combine this feature with GroupBar to allow users to drag-drop column headers to group the tree store.
Please note that this feature requires using a TreeGrid or having the Tree feature enabled.

This snippet shows how the sample dataset used in the demo above is transformed:

const grid = new TreeGrid({
    // Original data
    data : [
        { id : 1, name : 'Project 1', children : [
            { id : 11, name : 'Task 11', status : 'wip', prio : 'high' },
            { id : 12, name : 'Task 12', status : 'done', prio : 'low' },
            { id : 13, name : 'Task 13', status : 'done', prio : 'high' }
        ]},
        { id : 2, name : 'Project 2', children : [
            { id : 21, name : 'Task 21', status : 'wip', prio : 'high' },
        ]}
    ],

    features : {
        treeGroup : {
            // Fields to build a new tree from
            levels : [ 'prio', 'status' ]
        }
    }
});

// Resulting data
[
    { name : 'low', children : [
        { name : 'done', children : [
            { id : 12, name : 'Task 12', status : 'done', prio : 'low' }
        ]}
    ]},
    { name : 'high', children : [
        { name : 'done', children : [
            { id : 13, name : 'Task 13', status : 'done', prio : 'high' }
        ]},
        { name : 'wip', children : [
            { id : 11, name : 'Task 11', status : 'wip', prio : 'high' },
            { id : 21, name : 'Task 21', status : 'wip', prio : 'low' }
        ]}
    ]}
]

Generated parent records are indicated with generatedParent and key properties. The first one is set to true and the latter one has a value for the group the parent represents.

This feature does not work when the store is configured with lazyLoad.

Summaries

You can also show summaries in each group row, by configuring columns with sum.

new Grid({
    features : { treeGroup : true },
    columns : [
        {
            text  : 'Name',
            field : 'name',
            flex  : 3,
            type  : 'tree'
        },
        {
            type  : 'number',
            text  : 'Capacity',
            field : 'capacity',
            flex  : 1,
            sum   : 'add'
        },
        {
            type  : 'number',
            text  : 'Crew',
            field : 'crew',
            flex  : 1,
            sum   : 'add'
        }
    ]
});

Important information

Using the TreeGroup feature comes with some caveats:

  • Generated parents are read-only, they cannot be edited using the default UI.
  • Moving nodes manually in the tree is not supported while it is grouped. The linked records have their own parentId fields, not linked to the original records value.
  • The generated structure is not meant to be persisted.
Please note that this feature is not supported in vertical mode in Scheduler. If the Grid is stateful, the group configuration will be stored, but only string based group levels (e.g. ['city']).

This feature is disabled by default.

Configs

15

Common

disabledInstancePlugin
listenersEvents

Other

expandParents: Boolean= true

Specify as true to make generated parents start expanded.

True to hide grouped columns. Only supported when using String to define levels.

An array of model field names or functions used to determine the levels in the resulting tree.

When supplying a function, it will be called for each leaf in the original data, and it is expected to return an atomic value used to determine which parent the leaf will be added to at that level.

const grid = new TreeGrid({
    features : {
        treeGroup : {
            levels : [
                // First level is determined by the value of the status field
                'status',
                // Second level by the result of this function
                // (which puts percentdone 0-9 in one group, 10-19 into another and so on)
                record => (record.percentDone % 10) * 10
            ]
        }
    }
});

The function form can also be used as a formatter/renderer of sorts, simply by returning a string:

const grid = new TreeGrid({
    features : {
        treeGroup : {
            levels : [
                record => `Status: ${record.status}`
            ]
        }
    }
});

Assigning null restores the tree structure to its original state.

parentCls: String= b-generated-parent

CSS class to apply to the generated parents.

parentRenderer: function

A function letting you format the text shown in the generated parent group levels. This method will be provided with the value produced by the column representing the grouped level. Each column's renderer method will be provided an extra isTreeGroup param to indicate that the value will be used for a generated parent. cellElement and other DOM specific args will be in the context of the tree column.

const grid = new Grid({
    features : {
        treeGroup : {
            hideGroupedColumns : true,
            levels             : [
                'priority'
            ],
            parentRenderer({ field, value, column, record }) {
                // For generated group parent, prefix with the grouped column text
                return column.text + ': ' + value;
            }
        }
    }
})
ParameterTypeDescription
dataObject

The rendering data representing the generated tree parent record

data.fieldString

The field representing this group level (e.g. 'priority')

data.value*

The value representing this group level (e.g. 'high')

renderDataObject

Object containing renderer parameters

renderData.cellElementHTMLElement

Cell element, for adding CSS classes, styling etc. Can be null in case of export.

data.columnColumn

The value representing this group level (e.g. 'high')

renderData.gridGridBase

This grid

data.recordModel

The first record for this parent

renderData.isExportBoolean

true if the record is being exported to Excel or a textual format, enabling special handling during export.

renderData.rowRow

The parent Row object. Can be null in case of export. Use the row's API to manipulate CSS class names.

Returns: String
parentSortFn: function

Optional sort function for the generated parent tree nodes.

const grid = new Grid({
    features : {
        treeGroup : {
            parentSortFn(parentA, parentB) {
                 return parentB.name.localeCompare(parentA.name, undefined, { numeric : true });
            }
        }
    }
})
ParameterTypeDescription
parentATreeParentNode

The first node to be compared

parentBTreeParentNode

The second node to be compared

Returns: Number -

A negative value means parentA comes before parentB, a positive after, and 0 or NaN means they are equal

Misc

clientInstancePlugin
localeClassLocalizable
localizableLocalizable

Properties

18

Common

disabledInstancePlugin

Class hierarchy

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

Other

isGrouped: Boolean

Indicates if the feature has applied grouping and the component uses a transformed version of the store.

An array of model field names or functions used to determine the levels in the resulting tree.

When supplying a function, it will be called for each leaf in the original data, and it is expected to return an atomic value used to determine which parent the leaf will be added to at that level.

const grid = new TreeGrid({
    features : {
        treeGroup : {
            levels : [
                // First level is determined by the value of the status field
                'status',
                // Second level by the result of this function
                // (which puts percentdone 0-9 in one group, 10-19 into another and so on)
                record => (record.percentDone % 10) * 10
            ]
        }
    }
});

The function form can also be used as a formatter/renderer of sorts, simply by returning a string:

const grid = new TreeGrid({
    features : {
        treeGroup : {
            levels : [
                record => `Status: ${record.status}`
            ]
        }
    }
});

Assigning null restores the tree structure to its original state.

The original store used by the component before applying grouping. Use this to modify / load data while tree grouping is active.

Lifecycle

configBase

Misc

clientInstancePlugin
localeHelperLocalizable
localeManagerLocalizable

Functions

30

Tree grouping

Clears the previously applied transformation, restoring data to its initial state.

Yields the same result as assigning null to levels.

// Restore original data
grid.clearGroups();

Transforms the data according to the supplied levels.

Yields the same result as assigning to levels.

// Transform into a tree with two parent levels
grid.group('status', record => (record.percentDone % 10) * 10);
ParameterTypeDescription
levels(String|Column|Model): any)[]

Field names or functions use to generate parents in resulting tree.

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

2

An object that represents a tree parent node.

ParameterTypeDescription
idString

Id of the parent node

fieldString

Which field is being used for the group level

expandedBoolean

true if the group level is expanded, false otherwise

keyString

Grouping key identifier for the group level

pathString

String that represents the path to that group level

clsString

CSS classes for the group level

childrenModel[]

Array of the children nodes

readOnlyBoolean

true if the group is on read-only state, false otherwise