How can I make the filter into a very simple one where there’s just a text box and it limits what is shown in the table as the user begins entering text? I want to be able to hide the complex search and condition specification functionality.
Hi,
then probably the FTS based search is the right approach. It will search for all attributes and depending on your config attributes on related entities with just a single input field. With the attribute defaultMode in the filter tag you can change the default behavior to be full text search (can be switched by the checkbox on the right of the screen).
It uses not the relation database to gather the information but a NoSQL based search index that stores the data in a proper way besides the relational database.
Bye
Mario
If the generic filter component looks too heavyweight for the task, just add some fields to the screen and use their values for filtering the datasource as explained in the Query Filter section.
See the customer-browse.xml screen in the screen-manipulation sample application.
If the full text search is set as default, you can also disable the checkbox by setting modeSwitchVisible=“false” in the filter definition as well. It is documented but easily overlooked.
How would you get it to filter as you type instead of having to hit the apply button?
Thx Mario & Berend. The FTS approach provides exactly the functionality I’m looking for. Unfortunately I agree with Konstantin that it is overkill. The table will never have that many rows and after each deployment you have to remember to do a number of manual steps --> set an application property in the DB, do some stuff in the JMX console, restart the application server and create a scheduled task. I will still end up needing to implement my own filter, but in the near term this works.
Also, as an alternative, how would you get it to filter when the user hits Enter in the textbox?
Currently it’s impossible to react on each key press in a TextField. We are working on this problem and will offer a solution later.
But you can easily react on Enter press or focus lost as follows:
public class CustomerBrowse extends AbstractLookup {
@Inject
private TextField filterNameField;
@Inject
private CollectionDatasource<Customer, UUID> customersDs;
@Override
public void init(Map<String, Object> params) {
filterNameField.addValueChangeListener(e -> customersDs.refresh());
}
}
With FTS it searches the text values of all fields including dates and numbers. I am having problems implementing this. I have tried to do it in JPQL but I haven’t figured out how to treat for example dates as strings. I’ve tried something like the below which didn’t work. The functionality works fine for just string values like e.comments.
<query>
<![CDATA[select e from sample$Customer e]]>
<filter>
<c>FUNCTION('TO_CHAR', e.date) like :component$filterField</c>
<or>
<c>e.comments like :(?i)component$filterField</c>
</or>
</filter>
</query>
Is there a way to do it in JPQL? If not, can you do it in the value change listener of the filter field? Do you iterate through getItems() of the DS and include or exclude items that match? If you exclude an item, is it just excluded from the view and not from getItems()?
Answered my own question regarding how to do it in code. The results are below in case they are useful to anyone. Would still like to know if it could be done in JPQL.
static SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
@Inject
private TextField filterField;
@Inject
private CollectionDatasource<Customer, UUID> CustomersDs;
@Override
public void init(Map<String, Object> params) {
// will refresh on Enter or focus lost
filterField.addValueChangeListener((ValueChangeEvent e) -> applyFilter());
}
public void applyFilter() {
if (null == filterField) {
return;
}
CustomersDs.refresh();
String val = filterField.getValue();
if (null == val) {
val = "";
}
Collection<Customer> cs = CustomersDs.getItems();
for (Customer c : cs) {
check(c, val);
}
}
private void check(Customer c, String val) {
String c = c.getComments();
Date d = c.getDate();
if (null != c) {
if (c.contains(val)) {
CustomersDs.includeItem(c);
return;
}
}
if (null != d) {
String formattedDate = sdf.format(d);
if (formattedDate.contains(val)) {
CustomersDs.includeItem(c);
return;
}
}
customersDs.excludeItem(c);
Hi Jonathan,
Filtering on the client tier is very ineffective from the performance point of view, so it should be used only as a last resort.
I’ve prepared an example of filtering similar to full-text search but using JPQL only. See the project here: GitHub - knstvk/cuba-sample-simple-filter
The idea is to use programmatic building of query in the controller and using cast EclipseLink JPQL function:
public class OrderBrowse extends AbstractLookup {
@Inject
private GroupDatasource<Order, UUID> ordersDs;
@Inject
private TextField filterField;
@Override
public void init(Map<String, Object> params) {
filterField.addValueChangeListener(e -> applyFilter());
}
public void applyFilter() {
String filterValue = filterField.getValue();
if (Strings.isNullOrEmpty(filterValue)) {
ordersDs.setQuery("select e from sf$Order e");
ordersDs.refresh();
} else {
ordersDs.setQuery("select e from sf$Order e where " +
"lower(e.customer) like :custom$filterValue or " +
"cast(e.amount varchar(100)) like :custom$filterValue or " +
"cast(e.date varchar(100)) like :custom$filterValue");
ordersDs.refresh(ParamsMap.of("filterValue", "%" + filterValue.toLowerCase() + "%"));
}
}
}
Thanks. That works well.
Hi,
What if, instead of customer/amount or date I have country type enum?
I saw that displaying the String values of enum elements instead of their int ID values is not supported for JPQL datasets, only Entities and List of entities.