Search code examples
vaadin-grid

Vaadin 24 Grid refuses to render Column with ComponentRenderer


I am using Vaadin 24.2.3 and Java 17. Browser is mostly Chrome, but also tried with others.

I am trying to render a Grid with two Columns, one of them should render multi line text. My data provider delivers the correct values, the first column is rendered correctly; but so far for the second column either I do get just one single line of text or a completely empty output.

        ...
        Grid<JobMessageDetail> messageGrid = new Grid<>(JobMessageDetail.class, false);
        messageGrid.setWidthFull();
        messageGrid.setItems(filterDataProvider);
        messageGrid.addColumn(JobMessageDetail::getIdentifier)
                .setHeader("Identifier").setWidth("5em");  // rendered correctly

    // Variant one: results in one single line with all HTML tags rendered as text
        messageGrid.addColumn(
                LitRenderer.<JobMessageDetail>of("${item.messages}")
                .withProperty("messages", JobMessageDetail::getMessagesAsString))
            .setHeader("Messages").setWidth("50em");

    // Variant two: results in JavaScript error 
    // "There seems to be an error in Vaadin Grid: cannot read properties of undefined (reading 'getbynodeid')"
        messageGrid.addColumn(new ComponentRenderer<>(
                i -> {
                    Html result =  new Html(i.getMessagesAsString());
                    result.setId(String.valueOf(UUID.randomUUID()));
                    return result;
                }
                ))
            .setHeader("Messages").setWidth("50em");
    // Variant three: results in no content at all, even with fixed String list
        messageGrid.addColumn(LitRenderer.<JobMessageDetail>of(" <unsafe-html-component .html=${item.html}></unsafe-html-component>")
                .withProperty("html", i -> {
                    List<String> strings = List.of("item 1", "item 2", "item 3");
                    String listItems = "";
                    for (String eventItem : strings) {
                        listItems += "<li>"+eventItem +"</li>";
                    }
                    return listItems;
                }))
                .setHeader("Messages").setWidth("50em");

The value class JobMessageDetail:

@Getter
@Setter
@AllArgsConstructor
public class JobMessageDetail {
    private String identifier;
    private List<JobMessage> messages;

    public String getMessagesAsString() {
        return "<div>" + messages.stream()
                .map(x -> StringUtils.join("<b>", x.getMessageCode(), "</b>: ", x.getProperties()))
                .collect(Collectors.joining("<br>\n")) + "</div>";
    }
}

According to the JavaScript message I am completely lost how to fix; most of the solutions for multi line columns available are for Vaadin 14 or earlier, which are not applicable any more.

What am I missing or doing wrong? Which way to go for multi line columns? This issue seems not to be too exotic.

EDIT: I was able to enhance variant one by setting

messageGrid.addThemeVariants(GridVariant.LUMO_WRAP_CELL_CONTENT);

Now the text is wrapped, but I am not able to define where. Neither \n nor <br> does the job. Is it possible somehow?

EDIT 2: It seems, that Spring Java Live Reload gets in conflict with Vaadin ColumnRenderes. As I have removed the dependency for it, the ComponentRenderer works as expected. Maybe I should report that as a bug to the Vaadin team.


Solution

  • With default styles, a Html component should be enough, with GridVariant.LUMO_WRAP_CELL_CONTENT. You can use <br> where you want line breaks. Example:

    package com.vaadin.starter.skeleton;
    
    import com.vaadin.flow.component.Html;
    import com.vaadin.flow.component.grid.Grid;
    import com.vaadin.flow.component.grid.GridVariant;
    import com.vaadin.flow.component.orderedlayout.VerticalLayout;
    import com.vaadin.flow.router.Route;
    import org.apache.commons.lang3.StringUtils;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Random;
    import java.util.stream.Collectors;
    
    /**
     * The main view contains a button and a click listener.
     */
    @Route("")
    public class MainView extends VerticalLayout {
    
        public static class JobMessageDetail {
            private List<String> messages = new ArrayList<>();
    
            public JobMessageDetail(String s) {
                Random random = new Random();
                int count = random.nextInt(8) + 2;
                for (int i = 0; i < count; i++) {
                    if (i == 1) {
                        messages.add("This is a very long long long long long long long<br> long long long long long line");
                    } else {
                        messages.add(s + i);
                    }
                }
            }
    
            public String getMessagesAsString() {
                return "<div>" + messages.stream()
                        .map(x -> StringUtils.join("<b>", x, "</b>: ", "1,2,3"))
                        .collect(Collectors.joining("<br>")) + "</div>";
            }
        }
    
        public MainView() {
            setSizeFull();
            Grid<JobMessageDetail> grid = new Grid<>();
            grid.setSizeFull();
            grid.setItems(new JobMessageDetail("foo"), new JobMessageDetail("bar"), new JobMessageDetail("baz"), new JobMessageDetail("quux"));
            grid.addColumn(s -> s).setHeader("First");
            grid.addComponentColumn(s -> new Html(s.getMessagesAsString()));
            grid.addThemeVariants(GridVariant.LUMO_WRAP_CELL_CONTENT);
            add(grid);
        }
    
    
    }
    

    enter image description here