Refresh a TreeGrid while preserving the collapse/expand-state

I’m trying to refresh a TreeGrid in Vaadin 14 using treeGrid.setTreeData(newTreeData); treeGrid.getDataProvider().refreshAll();.

This works fine, but unfortunately the grid’s nodes’ lose their collapse/expand states. I stronlgy guess this is the expected behaviour.

In order to keep the states I guess I must not reset the TreeData, but modify it. Therefore I need to determine the diff between two TreeData objects.

But before I start implementing a solution, am I missing something?

I am having the same issue. I update an expanded parent’s children and then refresh the parent and the children. Unfortunately parent is collapsing after the refresh.I call expand on parent after refresh but nothing happens (calling isExpanded on parent returns true although parent is now collapsed in GUI)

Hi,

That might be related to this bug: https://github.com/vaadin/vaadin-grid/issues/1820 but it should be released in the Vaadin 14 (14.4.3+).

Which version of Vaadin 14 are your using?

I’ve used 14.4.2 and just updated to 14.4.4. But it seems to behave the same way as before:

  • if I set new TreeData with setTreeData(...), I still have to maintain the expanded nodes and call expand(expandedNodes) after refreshing. expandedNodes is maintained with
        treeGrid.addExpandListener(e -> expandedNodes.addAll(e.getItems()));
        treeGrid.addCollapseListener(e -> expandedNodes.removeAll(e.getItems()));
  • it flickers
  • if I update the initial TreeData instance instead of using a new one, refreshAll() keeps the states, but the TreeGrid flickers, too

This is my code to sync two TreeData instances, maybe it’s useful for someone else, too:

public class TreeDataSynchronizer {

    <T> void sync(TreeData<T> from, TreeData<T> to) {
        Queue<T> queue = new LinkedList<>();
        queue.add(null); // root node
		
        while (! queue.isEmpty()) {
            T currentItem = queue.poll();
            List<T> expectedChildren = from.getChildren(currentItem);
            update(to, currentItem, expectedChildren);
            queue.addAll(expectedChildren);
        }
    }

    private <T> void update(TreeData<T> td, T parent, List<T> listOfExpectedChildren) {
        Queue<T> expectedChildren = new LinkedList<>(listOfExpectedChildren);
        Queue<T> currentChildren = new LinkedList<>(td.getChildren(parent));

        while (!expectedChildren.isEmpty()) {
            T expectedChild = expectedChildren.poll();
            T currentChild = currentChildren.poll();
            while (!Objects.equals(currentChild, expectedChild)) {
                if (currentChild == null) {
                    td.addItem(parent, expectedChild);
                    break;
                }
                td.removeItem(currentChild);
                currentChild = currentChildren.poll();
            }
        }
		
		if (expectedChildren.isEmpty()) {
            currentChildren.forEach(td::removeItem);
        }

    }
}

if I update the initial TreeData instance instead of using a new one, refreshAll() keeps the states, but the TreeGrid flickers, too

Yes, that is unfortunately true. You can see the same effect also with this live code example

https://cookbook.vaadin.com/treegrid-subtree-highlight

I added a ticket in our issue tracker about this https://github.com/vaadin/vaadin-grid/issues/2109