tabulator icon indicating copy to clipboard operation
tabulator copied to clipboard

Tree misaligned in 5.5, items change indentation when expanded/collapsed.

Open ogheorghies opened this issue 6 months ago • 7 comments

Describe the bug Tree nodes of various depths are aligned inconsistently. A node moves to the right when first collapsed; its children are moved to the left when expanded back.

Tabulator Info 5.5

Working Example 5.4 reference: https://jsfiddle.net/5wkmfh1o/135/ 5.5 regression: https://jsfiddle.net/4qg2Lomh/6/

To Reproduce Collapse, then expand the node "L 3 << Collapse/Expand".

Expected behavior Alignment in 5.5 identical to that in 5.4. The node that is collapsed/expanded and its children do not change their indentation.

Screenshots

Desktop: MacOS Chrome 19.0.6045.199

ogheorghies avatar Dec 12 '23 16:12 ogheorghies

The problem is reproduced about half of the time: refresh repeatedly to see the change in alignment. https://jsfiddle.net/4qg2Lomh/6/

ogheorghies avatar Dec 12 '23 16:12 ogheorghies

The indentation is created by assigning a left margin to the branch element (the HTML element that shows the corner/angle). Investigation shows that the width of this element is 0 for newly created tree children. This leads to wrong indentation, which is computed based on that width (so it gets worse with every further indentation level).

When the branch element is inserted it gets its initial width, but not when it is inserted the first time, which is the cause of the trouble. I cannot say why this is so, however.

mike-lischke avatar Mar 06 '24 14:03 mike-lischke

do we have a work-around?

novecento avatar Mar 06 '24 17:03 novecento

I'm afraid this is a fundamental problem. A new row is initialized in the virtual renderer before it is added to the DOM. This causes the branch element to stay with width 0, which ruins the indentation computation (which is done in the initialization step).

A possible solution would be to move the layoutRow() call from the the "row-layout-after" event to any of the methods called for each row, after the row fragment has been added to the DOM. @olifolkerd would have to decide if that a good approach and how to change the current one.

mike-lischke avatar Mar 07 '24 11:03 mike-lischke

is it fixed on 6 ? tnx

novecento avatar Mar 19 '24 14:03 novecento

If the issue is still open it hasn't been fixed

olifolkerd avatar Mar 19 '24 19:03 olifolkerd

Here are two possible workarounds:

Option 1

  1. Use your own expander element.
  2. Set the standard branch element width to 0 in your CSS.
  3. Assign a proper value to the dataTreeChildIndent (e.g. 16, which is a common width).

An example for the options to use:

        const result: Options = {
            index: options?.index ?? "id",
            columns,
            data: tableData,
            frozenRows,

            dataTree: options?.treeColumn != null,
            dataTreeChildIndent: options?.treeChildIndent ?? 16,
            dataTreeExpandElement: "<span class='treeToggle' />",
            dataTreeCollapseElement: "<span class='treeToggle expanded' />",
            dataTreeBranchElement: false,
...
        };

This set of options will do 2 things: hide the standard branch element and show yours instead.

And the style for the default branch element:

.msg.treeGrid.tabulator .tabulator-row .tabulator-cell .tabulator-data-tree-branch-empty {
    /*
     * Keep the (hidden) tree branch element from automatic shrinking, as that creates an odd visual effect.
     * Unfortunately, this element cannot be removed from the DOM, as it is used to determine the indentation.
     */
    flex: none;
    width: 0;
    height: 100%;
}

Option 2

If you don't want to use an own branch element you can alternatively do an explicit reformat of the row that was expanded:

    private reformatRowDelayed = (row: RowComponent): void => {
        // Reformat the children after a moment, to fix wrong indentation. This is a regression introduced
        // in Tabulator 5.5. Once this is fixed there, this method can be removed.
        setTimeout(() => {
            row.getTreeChildren().forEach((child) => {
                child.reformat();
            });
        }, 10);

    };

mike-lischke avatar Apr 16 '24 08:04 mike-lischke