flow-components icon indicating copy to clipboard operation
flow-components copied to clipboard

Provide columnId for grid context menu dynamic content handler

Open TatuLund opened this issue 3 years ago • 3 comments

Current API with GridContextMenu is like follows

contextMenu.setDynamicContentHandler(item -> {
     ...
});

This makes possible to populate the GridContextMenu based on item clicked.

However sometimes there is need dynamically populate the menu based on the specific column clicked as well.

Currently this is not possible since only method to get column info is in GridContextMenuOpenedEvent, which fired after DynamicContentHandler is processed.

contextMenu.addGridContextMenuOpenedListener(event -> {
    columnId event.getColumnId();
    ...
});

Thus there is a need for API like using BiFunction in the handler

contextMenu.setDynamicContentHandler((item,columnId) -> {
     ...
});

Note, this was possible in Vaadin 8.

TatuLund avatar Jul 28 '21 10:07 TatuLund

Possible workaround 1: Use DomEvent listener to observe contextmenu

     String expression = "function(){const col=element.getEventContext(event).column;return col ? col.id : '';}()";
     getElement().addEventListener("contextmenu", event -> {
          String colId = event .getEventData().getString(expression);
          Optional<Column<Bean>> column = getColumns().stream().filter(col -> colId.equals(col.getId().get())).findFirst();
          System.out.println("setting domevent column id: " + column.get().getId().get());
          domEventColumn = column.get();
     }).addEventData(expression);
     GridContextMenu<Bean> contextMenu = addContextMenu();
     contextMenu.setDynamicContentHandler(wab -> {
          System.out.println("dynamicContentHandler " + domEventColumn.getId().get());
          return true;
     });

Possible workaround 2: Use alternative approach, for example Popup add-on in component renderer

    personGrid.addComponentColumn(item -> {
         HorizontalLayout layout = new HorizontalLayout();
         Span text = new Span();
         text.setText(item.getName());
         layout.add(text);
         String id = "cell"+Math.abs(rand.nextInt());
         text.setId(id);
         Popup popup = new Popup();
         layout.add(popup);
         popup.setFor(id);
         VerticalLayout div = new VerticalLayout();
         Button button1 = new Button("Click "+item.getName());
         Button button2 = new Button("Delete");
         div.add(button1,button2);
         popup.add(div);
         layout.addClickListener(event -> {
              popup.setOpened(true);
         });
        return layout;
   }).setKey("name");

TatuLund avatar Jul 29 '21 05:07 TatuLund

In our application, this feature was required and we therefor created a custom grid-connector which adds this functionality. The duplicate issue #424 has a referenced PR (closed) which shows our current solution.

probert94 avatar Jun 23 '22 07:06 probert94

Wouldn't it be preferable to get the column-key or even the column-instance instead of the column-id? Like mentioned in https://stackoverflow.com/questions/77117774/get-vaadin-grid-column-by-its-id column-id seems more like a internal identifier and an existing getter of Grid isn't accessible: Grid#getColumnByInternalId()

Regardless what id/key we could get, the nicest way for me would be to get the column-instance directly like so (because I stored some additional data in the column):

contextMenu.setDynamicContentHandler((item,column) -> {
    ColumnData data = ComponentUtil.getData(column, ColumnData.class);
     ...
});

kevinkendzia avatar Apr 30 '24 07:04 kevinkendzia