Grid - Filter in HeaderRow, attached widget

Hello Everyone! :slight_smile:

I am using Grid Component in my Vaadin application. I have following function to initialize my columns:

private void prepareColumns() { removeAllColumns(); final HeaderRow filterInputRow = appendHeaderRow(); final HeaderRow filterOptionRow = appendHeaderRow(); for (Map.Entry < String, String > columnEntry: columns.entrySet()) { final Column column = addColumn(columnEntry.getKey()); column.setHidable(true); column.setHeaderCaption(columnEntry.getValue()); column.setWidthUndefined(); final HeaderCell filterInputCell = filterInputRow.getCell(columnEntry.getKey()); final HeaderCell filterOptionCell = filterOptionRow.getCell(columnEntry.getKey()); switch (columnEntry.getKey()) { case "statusImage": column.setRenderer(new HtmlRenderer()); break; case "correlationId": column.setHidden(true); break; case "timestamp": column.setRenderer(new DateRenderer(new SimpleDateFormat("dd MMM yyyy HH:mm:ss", GWUI.get().getGWLocale()))); break; case "duration": column.setRenderer(new NumberRenderer("%d")); filterInputCell.setComponent(createFilter(columnEntry.getKey())); filterOptionCell.setComponent(createNumberOptionGroup()); break; default: filterInputCell.setComponent(createFilter(columnEntry.getKey())); filterOptionCell.setComponent(createTextOptionGroup()); break; } } } Everytime I reload component I got following errors in web console (taken from Chrome web console):

SEVERE: Widget is still attached to the DOM after the connector (CssLayoutConnector (89)) has been unregistered. Widget was removed. I noticed that when I disable adding additional header rows the error does not appear. Does anyone encounter this problem?

Thanks in advance!

Kamil

I have the same problem. :frowning:
Any solution?

Do you have a CssLayout defined somewhere? I can’t see where that is?

I don’t use Css Layout, but the error message is the same. Ok, almost the same, exactly (this is a JS error!):

Fri Aug 19 13:18:28 GMT+200 2016 com.vaadin.client.VConsole SEVERE: Widget is still attached to the DOM after the connector (TextFieldConnector (182)) has been unregistered. Widget was removed. http://localhost:8181/alumni/#!/html/body/script (27) Line 1 In the TomCat console log:

aug. 19, 2016 13:18:27 DE com.vaadin.ui.ConnectorTracker unregisterConnector
WARNING: Unregistered TextField (182) that was already unregistered.

I’ve (tried :slight_smile: ) created a general filters for a grid. Simple filters: text contains and date range.
The superclass has a method which adds a header row to grid (if not extists) and walks throught container properties and takes filter column by the property class (String → text filter, Date → date filter).

Here it is a part of the superclass (… extends Grid) :

    protected LazyQueryContainer containter;
    protected HeaderRow filterRow = null;
    
    public void setContainer(LazyQueryContainer containter) {
        this.containter = containter;
        setContainerDataSource(containter);
        addFilterRow();
    }
    
    protected void removeColFilter(String pid, LazyQueryContainer container) {
        for (int i = 0; i < allColFilters.size(); i++) {
            String key = (String) allColFilters.get(i).getKey();
            if (key.equals(pid)) {
                container.removeContainerFilter((Filter) allColFilters.get(i).getValue());
                allColFilters.remove(i);
                return;
            }
        }
    }

    protected void addFilterRow() {
        if (containter == null || this.getHeaderRowCount() > 1) {
            return;
        }
        filterRow = appendHeaderRow();
        for (Object pid : containter.getContainerPropertyIds()) {
            HeaderCell cell = filterRow.getCell(pid);

            if (containter.getType(pid).toString().contains("java.util.Date")) {
                DateField filterDFieldFrom = new DateField();
                DateField filterDFieldTo = new DateField();

                filterDFieldFrom.setDateFormat("yyyy.MM.dd HH:mm:ss");
                filterDFieldTo.setDateFormat("yyyy.MM.dd HH:mm:ss");
                filterDFieldFrom.setResolution(Resolution.SECOND);
                filterDFieldTo.setResolution(Resolution.SECOND);

                filterDFieldFrom.addValueChangeListener(change -> {
                    removeColFilter(pid.toString(), containter);
                    if (filterDFieldFrom.getValue() != null || filterDFieldTo.getValue() != null) {
                        if (filterDFieldFrom.getValue() != null && filterDFieldTo.getValue() == null) {
                            Filter colFilter = new Compare.GreaterOrEqual(pid,
                                    filterDFieldFrom.getValue());
                            containter.addContainerFilter(colFilter);
                            allColFilters.add(new AbstractMap.SimpleEntry(pid, colFilter));
                        }
                        if (filterDFieldFrom.getValue() == null && filterDFieldTo.getValue() != null) {
                            Filter colFilter = new Compare.LessOrEqual(pid,
                                    filterDFieldTo.getValue());
                            containter.addContainerFilter(colFilter);
                            allColFilters.add(new AbstractMap.SimpleEntry(pid, colFilter));
                        }
                        if (filterDFieldFrom.getValue() != null && filterDFieldTo.getValue() != null) {
                            Filter colFilter = new Between(pid,
                                    filterDFieldFrom.getValue(),
                                    filterDFieldTo.getValue());
                            containter.addContainerFilter(colFilter);
                            allColFilters.add(new AbstractMap.SimpleEntry(pid, colFilter));
                        }
                    } else {
                        containter.refresh();
                    }
                });

                filterDFieldTo.addValueChangeListener(change -> {
                    removeColFilter(pid.toString(), containter);
                    if (filterDFieldTo.getValue() != null || filterDFieldFrom.getValue() != null) {
                        if (filterDFieldFrom.getValue() != null && filterDFieldTo.getValue() == null) {
                            Filter colFilter = new Compare.GreaterOrEqual(pid,
                                    filterDFieldFrom.getValue());
                            containter.addContainerFilter(colFilter);
                            allColFilters.add(new AbstractMap.SimpleEntry(pid, colFilter));
                        }
                        if (filterDFieldFrom.getValue() == null && filterDFieldTo.getValue() != null) {
                            Filter colFilter = new Compare.LessOrEqual(pid,
                                    filterDFieldTo.getValue());
                            containter.addContainerFilter(colFilter);
                            allColFilters.add(new AbstractMap.SimpleEntry(pid, colFilter));
                        }
                        if (filterDFieldFrom.getValue() != null && filterDFieldTo.getValue() != null) {
                            Filter colFilter = new Between(pid,
                                    filterDFieldFrom.getValue(),
                                    filterDFieldTo.getValue());
                            containter.addContainerFilter(colFilter);
                            allColFilters.add(new AbstractMap.SimpleEntry(pid, colFilter));
                        }
                    } else {
                        containter.refresh();
                    }
                });

                HorizontalLayout hl = new HorizontalLayout();
                hl.addComponents(filterDFieldFrom, new Label(" - "), filterDFieldTo);
                cell.setComponent(hl);
            } else {
                TextField filterField = new TextField();
                filterField.addTextChangeListener(change -> {
                    removeColFilter(pid.toString(), containter);
                    if (!change.getText().isEmpty()) {
                        Filter colFilter = new Like(pid, "%" + change.getText() + "%", false);
                        containter.addContainerFilter(colFilter);
                        allColFilters.add(new AbstractMap.SimpleEntry(pid, colFilter));
                    } else {
                        containter.refresh();
                    }
                });

                cell.setComponent(filterField);
            }
        }     
    }

(This is the first attempt. So probably not the final solution. :wink: )

Something I missed or misundertood… The problem:
when open a filtered grid - first time, after login - it works perfectly, no error.
Than I go to another view - to another filtered grid or there is not grid, doesn’t matter - the error raises. So when I leave that view the error raises.

It seems it generates some JS code for filter which is stuck in the page/view…
It seems something I missed…
What did I do wrong?

One more detail:
I call the “addFilterRow” method in the “attach” method of subclass.

I have tried with one, single “text filter field”.
And in the “detach” method of subclass I remove that one (filter) textfiled component.
But the error raises just like I wrote above. :frowning:

Ok, next approach. No generic/general solution. Everything is specific.

Here’s the AuditLog grid creator class, with one filter column:

[code]
public class AuditLogsGridCreator {

private Grid grid;
protected LazyQueryContainer containter;
private TextField ffEvent; // filter field for Event column

public AuditLogsGridCreator(LazyQueryContainer containter) {
    this.containter = containter;
    
    createGrid();
    addFilters();
}

private void addFilters() {
    Object pid = "event";
    HeaderRow filterRow = this.grid.appendHeaderRow();
    Grid.HeaderCell cell = filterRow.getCell(pid);
    ffEvent = new TextField();
    ffEvent.addTextChangeListener((change) -> {
        if (!change.getText().isEmpty()) {
            Container.Filter colFilter = new Like(pid, "%" + change.getText() + "%", false);
            this.containter.addContainerFilter(colFilter);
        } else {
            this.containter.refresh();
        }
    });
    cell.setComponent(ffEvent);
}

private void createGrid() throws IllegalArgumentException, IllegalStateException {
    this.grid = new Grid(this.containter);
    this.grid.setSizeFull();
    
    this.grid.getColumn("id").setHeaderCaption("ID");
    this.grid.getColumn("event").setHeaderCaption("Event");
    this.grid.getColumn("source").setHeaderCaption("Source");
    this.grid.getColumn("functionName").setHeaderCaption("Fnc.");
    this.grid.getColumn("clientInfo").setHeaderCaption("Client");
    this.grid.getColumn("created").setHeaderCaption("Created");
    this.grid.getColumn("userName").setHeaderCaption("User");
    
    this.grid.getColumn("event").setWidth(800);
}

public Grid getGrid() {
    return this.grid;
}

public TextField getFfEvent() {
    return ffEvent;
}

public void setFfEvent(TextField ffEvent) {
    this.ffEvent = ffEvent;
}

}
[/code]Calling in the “view class”:

[...]

private void createContent() {
        
        LazyQueryContainer items = new LazyQueryContainer(this.auditlogsService.lazyLoadData(), "id", 50, false);

        items.addContainerProperty("id", Long.class, 0L, true, true);
        items.addContainerProperty("event", String.class, "", true, true);
        items.addContainerProperty("source", String.class, "", true, true);
        items.addContainerProperty("functionName", String.class, "", true, true);
        items.addContainerProperty("clientInfo", String.class, "", true, true);
        items.addContainerProperty("created", Date.class, "", true, true);
        items.addContainerProperty("userName", String.class, "", true, true);
      
        this.table = new AuditLogsGridCreator(items);

        addComponents(table.getGrid());
    }
[...]

The error raises when I go throught views/grids. Just right I wrote previous post…
:frowning:

I did miss something… but what?