Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TreeGrid#getDataProvider().refreshItem(parent, true); does not remove expanded state if item does not have any children anymore #21097

Open
randomuser1231232 opened this issue Mar 6, 2025 · 2 comments

Comments

@randomuser1231232
Copy link

randomuser1231232 commented Mar 6, 2025

Description of the bug

TreeGrid#getDataProvider().refreshItem(parent, true); does not remove expanded state if item does not have any children anymore.

Used Dataprovider: AbstractBackEndHierarchicalDataProvider

Expected behavior

Remove expanded state for item after TreeGrid#getDataProvider().refreshItem(parent, true) if item does not have any children anymore.

Minimal reproducible example

@Route
public class MainView extends VerticalLayout {

    public MainView() {
        final var treegrid = new TestTreeGrid();
        final var addButton = new Button("add");
        addButton.addClickListener(buttonClickEvent -> {
            for (UUID item : treegrid.getSelectedItems()) {
                treegrid.add(item, UUID.randomUUID());
                treegrid.add(item, UUID.randomUUID());
            }
        });
        final var deleteButton = new Button("delete children");
        deleteButton.addClickListener(buttonClickEvent -> {
            for (UUID item : treegrid.getSelectedItems()) {
                treegrid.deleteChildren(item);
            }
        });

        this.add(addButton, deleteButton, treegrid);
    }
}
public class TestTreeGrid extends TreeGrid<UUID> {

    private final Map<UUID, List<UUID>> childMap;

    public TestTreeGrid() {
        UUID root = UUID.randomUUID();
        childMap = new HashMap<>();
        this.setWidth(600, Unit.PIXELS);
        this.setHeight(800, Unit.PIXELS);

        addHierarchyColumn(i -> i);
        setDataProvider(new AbstractBackEndHierarchicalDataProvider<UUID, Object>() {
            @Override
            protected Stream<UUID> fetchChildrenFromBackEnd(HierarchicalQuery<UUID, Object> query) {
                if (query.getParent() == null) {
                    return Stream.of(root);
                }
                return childMap.get(query.getParent()).stream();
            }

            @Override
            public int getChildCount(HierarchicalQuery<UUID, Object> query) {
                if (query.getParent() == null) {
                    return 1;
                }
                return childMap.get(query.getParent()).size();
            }

            @Override
            public boolean hasChildren(UUID item) {
                return childMap.containsKey(item) && !childMap.get(item).isEmpty();
            }
        });
    }

    public void add(UUID parent, UUID child) {
        var children = this.childMap.get(parent);
        if (children == null) {
            children = new ArrayList<>();
        }
        children.add(child);
        childMap.put(parent, children);

        this.expand(parent);
        this.getDataProvider().refreshItem(parent, true);
        this.select(child);
    }

    public void deleteChildren(UUID parent) {
        var children = this.childMap.get(parent);
        if (children == null || children.isEmpty()) {
            return;
        }
        children.clear();

        this.getDataProvider().refreshItem(parent, true);
    }

}
vaadin-grid::part(expanded-row-cell) {
  background-color: green;
}
  1. select root
  2. add children
  3. remove children
  4. css above is still applied to cells

Versions

  • Vaadin / Flow version:24.6.5
@tepi
Copy link
Contributor

tepi commented Mar 19, 2025

Not 100% sure if this is a bug or not. To me it seems the expanded/collapsed state and existence of children are independent state-like properties of a parent node, so doing this in your example code at least 'fixes' the issue for this case:

public void deleteChildren(UUID parent) {
    var children = this.childMap.get(parent);
    if (children == null || children.isEmpty()) {
        return;
    }
    children.clear();
    this.collapse(parent); // <-- collapse the parent node
    this.getDataProvider().refreshItem(parent, true);
}

@tepi tepi moved this from ⚒️ In progress to 🅿️Parking lot in Vaadin Flow ongoing work (Vaadin 10+) Mar 19, 2025
@tepi
Copy link
Contributor

tepi commented Mar 19, 2025

Tagging as waiting for author since I think the author might have some more input on this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: 🔎 Investigation
Status: 🅿️Parking lot
Development

No branches or pull requests

3 participants