• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

knowledgepixels / nanodash / 26622127697

29 May 2026 06:33AM UTC coverage: 20.725% (-0.007%) from 20.732%
26622127697

push

github

tkuhn
feat: apply view filters live as the user types

Filter text fields used AjaxFormComponentUpdatingBehavior("change"),
which only fires on blur/Enter, so the filter required pressing Enter.

Add a reusable FilterUpdatingBehavior that listens on the "input" event
(fires per keystroke) with a 300ms debounce so rapid typing coalesces
into a single request. Swap it into all filter fields.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

1003 of 6148 branches covered (16.31%)

Branch coverage included in aggregate %.

2584 of 11160 relevant lines covered (23.15%)

3.31 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
src/main/java/com/knowledgepixels/nanodash/component/ItemList.java
1
package com.knowledgepixels.nanodash.component;
2

3
import com.knowledgepixels.nanodash.component.ItemListPanel.ComponentProvider;
4
import com.knowledgepixels.nanodash.FilteredListDataProvider;
5
import org.apache.wicket.ajax.AjaxRequestTarget;
6
import org.apache.wicket.ajax.markup.html.navigation.paging.AjaxPagingNavigator;
7
import org.apache.wicket.extensions.markup.html.repeater.data.table.NavigatorLabel;
8
import org.apache.wicket.markup.html.WebMarkupContainer;
9
import org.apache.wicket.markup.html.form.TextField;
10
import org.apache.wicket.markup.html.panel.Panel;
11
import org.apache.wicket.markup.repeater.Item;
12
import org.apache.wicket.markup.repeater.data.DataView;
13
import org.apache.wicket.markup.repeater.data.ListDataProvider;
14
import org.apache.wicket.model.IModel;
15
import org.apache.wicket.model.Model;
16

17
import java.io.Serializable;
18
import java.util.List;
19

20
/**
21
 * A reusable Wicket panel that displays a paginated list of items.
22
 *
23
 * @param <T> the type of items in the list, must be Serializable
24
 */
25
public class ItemList<T extends Serializable> extends Panel {
26

27
    /**
28
     * Creates an ItemList panel.
29
     *
30
     * @param markupId     the markup ID for the panel
31
     * @param items        the list of items to display
32
     * @param compProvider a provider that generates a component for each item
33
     */
34
    public ItemList(String markupId, List<T> items, ComponentProvider<T> compProvider) {
35
        this(markupId, items, compProvider, null);
×
36
    }
×
37

38
    /**
39
     * Creates an ItemList panel with optional filter.
40
     *
41
     * @param markupId        the markup ID for the panel
42
     * @param items           the list of items to display
43
     * @param compProvider    a provider that generates a component for each item
44
     * @param filterTextGetter function to get searchable text from each item, or null for no filter (must be serializable for Wicket page serialization)
45
     */
46
    public ItemList(String markupId, List<T> items, ComponentProvider<T> compProvider, FilteredListDataProvider.SerializableFunction<T, String> filterTextGetter) {
47
        this(markupId, items, compProvider, filterTextGetter, null);
×
48
    }
×
49

50
    /**
51
     * Creates an ItemList panel with filter in external panel (filter field is in parent; filterModel is shared).
52
     */
53
    public ItemList(String markupId, List<T> items, ComponentProvider<T> compProvider, FilteredListDataProvider.SerializableFunction<T, String> filterTextGetter, IModel<String> filterModel) {
54
        super(markupId);
×
55
        setOutputMarkupId(true);
×
56

57
        final DataView<T> dataView;
58
        if (filterTextGetter != null) {
×
59
            IModel<String> effectiveFilterModel = filterModel != null ? filterModel : Model.of("");
×
60
            FilteredListDataProvider<T> filteredDataProvider = filterModel != null
×
61
                    ? new FilteredListDataProvider<>(items, filterTextGetter, filterModel)
×
62
                    : new FilteredListDataProvider<>(items, filterTextGetter);
×
63
            dataView = new DataView<T>("itemlist", filteredDataProvider) {
×
64
                @Override
65
                protected void populateItem(Item<T> item) {
66
                    item.add(compProvider.apply(item.getModelObject()));
×
67
                }
×
68
            };
69
            if (filterModel == null) {
×
70
                TextField<String> filterField = new TextField<>("filter", effectiveFilterModel);
×
71
                filterField.setOutputMarkupId(true);
×
72
                filterField.add(new FilterUpdatingBehavior() {
×
73
                    @Override
74
                    protected void onUpdate(AjaxRequestTarget target) {
75
                        filteredDataProvider.setFilterText(effectiveFilterModel.getObject());
×
76
                        WebMarkupContainer nav = (WebMarkupContainer) ItemList.this.get("navigation");
×
77
                        nav.setVisible(dataView.getPageCount() > 1);
×
78
                        target.add(ItemList.this);
×
79
                    }
×
80
                });
81
                add(filterField);
×
82
            } else {
×
83
                add(new TextField<>("filter", Model.of("")).setVisible(false));
×
84
            }
85
        } else {
×
86
            dataView = new DataView<T>("itemlist", new ListDataProvider<T>(items)) {
×
87
                @Override
88
                protected void populateItem(Item<T> item) {
89
                    item.add(compProvider.apply(item.getModelObject()));
×
90
                }
×
91
            };
92
            add(new TextField<>("filter", Model.of("")).setVisible(false));
×
93
        }
94

95
        dataView.setItemsPerPage(10);
×
96
        dataView.setOutputMarkupId(true);
×
97
        add(dataView);
×
98

99
        WebMarkupContainer navigation = new WebMarkupContainer("navigation");
×
100
        navigation.add(new NavigatorLabel("navigatorLabel", dataView));
×
101
        AjaxPagingNavigator pagingNavigator = new AjaxPagingNavigator("navigator", dataView);
×
102
        navigation.setVisible(dataView.getPageCount() > 1);
×
103
        navigation.add(pagingNavigator);
×
104
        add(navigation);
×
105
    }
×
106

107
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc