Search code examples
javauser-interfacedatatablegwtdomino-ui

Using domino-ui datatable search action with remote data store


what is the proper way to connect the SearchTableAction header with a server-side search? (Right now the example uses the LocalListDataStore and filters it client-side via a SearchFilter, Regular GWT would use CellTables and AsyncDataProvider)

The winning option right now (which does not seem ideal) would be to copy SearchTableAction UI setup in the constructor and create a new class that would call setData on the LocalDataStore after the server-side call finishes.


Solution

  • You dont actually need to copy the UI, the search action as well the header filters will fire a table event when they are changed, any data store can listen to those events and read the search filters from the event and use it to load/filter the data, the LocalDatStore does this and filter the data locally, a remote data store will read these filters and sends them to the server and the server will filter the data and return the result to the client.

    Here is a sample remote data store

    package org.dominokit.domino.ui.sample.store;
    
    import org.dominokit.domino.ui.sample.client.Formats;
    import org.dominokit.domino.ui.sample.shared.store.CanLoadItems;
    import org.dominokit.domino.ui.sample.shared.store.LoadContext;
    import org.dominokit.domino.ui.datatable.events.SearchEvent;
    import org.dominokit.domino.ui.datatable.events.SortEvent;
    import org.dominokit.domino.ui.datatable.events.TableEvent;
    import org.dominokit.domino.ui.datatable.events.TablePageChangeEvent;
    import org.dominokit.domino.ui.datatable.model.Filter;
    import org.dominokit.domino.ui.datatable.model.FilterTypes;
    import org.dominokit.domino.ui.datatable.store.DataChangedEvent;
    import org.dominokit.domino.ui.datatable.store.DataStore;
    import org.dominokit.domino.ui.datatable.store.StoreDataChangeListener;
    import org.dominokit.domino.ui.pagination.HasPagination;
    import org.gwtproject.i18n.client.DateTimeFormat;
    
    import java.util.*;
    
    import static java.util.Objects.nonNull;
    import static org.dominokit.domino.ui.datatable.events.SearchEvent.SEARCH_EVENT;
    import static org.dominokit.domino.ui.datatable.events.SortEvent.SORT_EVENT;
    
    public class RemoteDataStore<T> implements DataStore<T> {
        private List<StoreDataChangeListener<T>> listeners = new ArrayList<>();
        private HasPagination pagination;
        private CanLoadItems<T> uiHandlers;
        private String propertyName;
        private String sortDirection;
        private int activePage = 0;
    
        private Map<String, String> searchProperties = new HashMap<>();
        private List<T> items;
    
        public RemoteDataStore(CanLoadItems<T> uiHandlers) {
            this.uiHandlers = uiHandlers;
        }
    
        @Override
        public void onDataChanged(StoreDataChangeListener<T> dataChangeListener) {
            listeners.add(dataChangeListener);
        }
    
        @Override
        public void removeDataChangeListener(StoreDataChangeListener<T> dataChangeListener) {
            listeners.remove(dataChangeListener);
        }
    
        @Override
        public void load() {
            uiHandlers.load(getLoadContext(), loadResult -> {
                this.items = loadResult.getResourceList();
                if (nonNull(loadResult.getPage())) {
                    pagination.updatePagesByTotalCount(loadResult.getPage().getTotalElements(), loadResult.getPage().getSize());
                    pagination.gotoPage(loadResult.getPage().getNumber() + 1, true);
                }
                fireUpdate();
            });
        }
    
        private LoadContext getLoadContext() {
            return new LoadContext(propertyName, sortDirection, activePage, searchProperties);
        }
    
        @Override
        public void handleEvent(TableEvent event) {
            switch (event.getType()) {
                case TablePageChangeEvent.PAGINATION_EVENT:
                    activePage = pagination.activePage() - 1;
                    load();
                    break;
                case SORT_EVENT:
                    propertyName = ((SortEvent<?>) event).getColumnConfig().getName();
                    sortDirection = ((SortEvent<?>) event).getSortDirection().toString();
                    load();
                    break;
                case SEARCH_EVENT:
                    searchProperties = new HashMap<>();
                    List<Filter> filters = ((SearchEvent) event).getFilters();
                    this.activePage = 0;
                    for (Filter filter : filters) {
                        if (!filter.getValues().isEmpty()) {
                            if (filter.getType().equals(FilterTypes.DATE)) {
                                String longDate = filter.getValues().get(0);
                                String formattedDate = DateTimeFormat.getFormat(Formats.DEFAULT_DATE_PATTERN)
                                        .format(new Date(Long.parseLong(longDate)));
                                searchProperties.put(filter.getFieldName(), formattedDate);
                            } else {
                                searchProperties.put(filter.getFieldName(), filter.getValues().get(0));
                            }
                        }
                    }
                    load();
                    break;
            }
        }
    
        private void fireUpdate() {
            listeners.forEach(dataChangeListener -> dataChangeListener.onDataChanged(new DataChangedEvent<>(items, items.size())));
        }
    
        public HasPagination getPagination() {
            return pagination;
        }
    
        public void setPagination(HasPagination pagination) {
            this.pagination = pagination;
        }
    
        public int getActivePage() {
            return activePage;
        }
    
        public void load(int pageNumber) {
            this.activePage = pageNumber;
            load();
        }
    }
    

    Here we listen to the events and delegate the actual data load call to the uiHandlers.

    Notice that implementing a remote data store depends on the server implementation, so there is no one remote data store that works for everyone, so use this as an example to implement one that works for your server.