flow icon indicating copy to clipboard operation
flow copied to clipboard

TreeGrid w/TreeData and Drag & Drop does not internally update. See video.

Open enver-haase opened this issue 3 months ago • 3 comments

Description of the bug

This is about DX, but I would consider it a bug rather than a feature. TreeData and TreeGrid are Vaadin-provided classes. I feel I should not need to learn about DataCommunicator or that internally the TreeData is wrapped with some HierarchicalDataProvider or such. I should be able to manipulate the TreeData and see the results.

As a bare minimum, this would need to be documented very thoroughly, including how to avoid scrolling or "jumping" when updating.

Expected behavior

Dragging and dropping should not only have an effect in the TreeData, I should immediately see those changes.

Minimal reproducible example

package org.vaadin.example;

import com.vaadin.flow.component.grid.Grid; import com.vaadin.flow.component.grid.dnd.GridDropLocation; import com.vaadin.flow.component.grid.dnd.GridDropMode; import com.vaadin.flow.component.notification.Notification; import com.vaadin.flow.component.treegrid.TreeGrid;

import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.data.provider.hierarchy.TreeData; import com.vaadin.flow.router.Route;

import java.util.ArrayList; import java.util.List;

@Route public class MainView extends VerticalLayout {

private static class DemoTreeData extends TreeData<String> {
    private DemoTreeData() {
        final String[] five = {"A", "B", "C", "D", "E"};

        addRootItems(five);

        for (String s : five) {
            List<String> children = new ArrayList<>();
            for (String ch : five) {
                String child = s+ch;
                children.add(child);
            }

            addItems(s, children);
        }
    }
}
public MainView() {

    TreeGrid<String> treeGrid = new TreeGrid<>();

    treeGrid.addHierarchyColumn(String::toString).setHeader("Name");

    treeGrid.setTreeData(new DemoTreeData());

    treeGrid.setDropMode(GridDropMode.ON_TOP_OR_BETWEEN);
    treeGrid.setSelectionMode(Grid.SelectionMode.SINGLE);
    treeGrid.setRowsDraggable(true);

    List<String> dragged = new ArrayList<>();
    treeGrid.addDragStartListener( evt -> {
        dragged.clear();
        dragged.addAll(evt.getDraggedItems());
    } );

    treeGrid.addDropListener( evt -> {
        try {
            if (GridDropLocation.ON_TOP == evt.getDropLocation()) {
                evt.getDropTargetItem().ifPresent(s -> {
                    for (String drag : dragged) {
                        treeGrid.getTreeData().removeItem(drag);
                        treeGrid.getTreeData().addItem(s, drag);
                    }
                });
                //treeGrid.getDataCommunicator().reset();
            }
        }
        catch (Exception e) {
            Notification.show("Exception: "+e);
        }
    } );

    treeGrid.setWidthFull();
    treeGrid.setHeight("800px");
    add(treeGrid);
}

}

Versions

  • Vaadin / Flow version: 24.3.10
  • Java version: n/a
  • OS version: n/a
  • Browser version (if applicable): n/a
  • Application Server (if applicable): n/a
  • IDE (if applicable): n/a

enver-haase avatar May 07 '24 15:05 enver-haase

https://github.com/vaadin/flow/assets/7870436/5e1ea524-1b23-42a6-9ec1-90763e5f1535

enver-haase avatar May 07 '24 15:05 enver-haase

Why do you use DataCommunicator? Isn't call the treeGrid.getDataProvider().refreshAll() be enough, that's a true public API for the component. Would be good to update the documentation (and javadocs) to mention that the data refresh is needed in this case: some methods in TreeData, e.g. setParent, have an instruction to call the TreeDataProvider#refreshAll(), but the above methods, used in the example, do not. Thus, we have to update the javadoc for all the method in TreeData at least, then online docs.

mshabarov avatar May 14 '24 10:05 mshabarov

Why not DataCommunicator?

Or, put differently, where in the documentation does it say HierarchicalDataProvider<T, SerializablePredicate<T>> getDataProvider() is the official API? It looks convoluted enough.

As I initially said (and the code has no getDataProvider() and has getDataComminicator() commented out) -- I feel one should not have to learn about the internal workings. A am setting a TreeData, not a DataProvider of any kind. Getting one DataProvider and notifying it that I changed the TreeData seems like really bad API. In fact, TreeData is a Vaadin class and should already have all the means to update the representation when the model is changed.

If it is true that some methods in TreeData correctly notify the DataProvider that's wrapped around it, then all the data-altering methods should correctly notify the DataProvider about the change.

enver-haase avatar May 14 '24 11:05 enver-haase