When data is stored in a database we want to be able to search for records. Searching is so common that DomUI has a special component that helps with creating database search screens: the SearchPanel. The Search Panel works on database objects, i.e. entity classes that are defined in Hibernate or JPA, or even with plain JDBC accessed objects (using DomUI's generic database layer). This means that working with the panel you stay inside the Java world.
Let's start with an example:
@Override public void createContent() throws Exception { ContentPanel cp = new ContentPanel(); add(cp); SearchPanel<Invoice> lf = new SearchPanel<>(Invoice.class); cp.add(lf); lf.setClicked(a -> search(lf)); lf.add().property("customer").control(); // Start with lookup by customer lf.add().property("total").control(); // Allow searching for a total lf.add().property("invoiceDate").control(); // And the date. }
This example creates a search panel which searches for Invoice instances using the customer, total (amount) and invoiceDate properties. The actual searching and showing of the data is done by base class which will be shown at the end of this document.
This fragment creates the following UI (LIVE - click inside to play with it):
As can be seen, each property is presented on the form, in order. And for each property we have a special "control" which allows for input related to the type of the property. We see, in order:
- The customer property uses a LookupInput2, because it is actually a @ManyToOne relation (parent) of the Invoice class. This control lets you search for a Customer using a special UI.
- The "total" field is a numeric field. It uses a special Lookup Control called NumberLookupControl which allows searching for a number as follows:
- Enter "> 1000" to find all records with an amount > 1000. Likewise you can use <, <=, >=.
- Entering a single amount searches for an exact match
- Entering 10% does a "like" query with all amounts that start by 10.
- The invoiceDate field creates another Lookup Control called DateLookupControl. This control shows two dates, and allows searched starting from, ending at or between the two dates.
The SearchPanel uses metadata to get the default label for properties, and it uses a registry of factories (LookupControlRegistry2) to find the best lookup control for a property, by type. The registry can be easily extended with your own lookup control factories.
You can control how data is shown using the builder pattern exhibited above. In that way you can change:
- The label by using label(String) or label(NodeContainer)
- The lookup hint (what is shown when hovering over the control) which also defaults to metadata
- The default value to use. This value will be used as the initial value of the control, and will also be used when the "reset" button is pressed on the panel.
- Whether a text search ignores case or not (defaults to true)
- The minimal input length for a control before the search is issued. This can be used to prevent large searches by specifying that at least 3 characters should be used for instance.
- Options specific for the control being created.
Using metadata with the panel
In the above example we specified what to search on by hand. This is often handy because it allows full control. But the form can also be populated automatically by using the metadata associated with the entity we look for. Take for example the following definition for Invoice's metadata:
@Entity @Table(name = "Invoice") @SequenceGenerator(name = "sq", sequenceName = "invoice_sq") @MetaObject(defaultColumns = { // 20180203 Must have metadata for SearchPanel/LookupForm tests. @MetaDisplayProperty(name = "customer.lastName", displayLength = 20) , @MetaDisplayProperty(name = "customer.firstName", displayLength = 10) , @MetaDisplayProperty(name = "invoiceDate") , @MetaDisplayProperty(name = "billingAddress", displayLength = 20) , @MetaDisplayProperty(name = "billingCity", displayLength = 10) , @MetaDisplayProperty(name = "total", displayLength = 10) } , searchProperties = { @MetaSearchItem(name = "invoiceDate") , @MetaSearchItem(name = "billingCity") , @MetaSearchItem(name = "customer") } )
The searchProperties above are the "default" properties to use inside the SearchPanel, and they take effect when no manual configuration of the SearchPanel is done, like this:
@Override public void createContent() throws Exception { ContentPanel cp = new ContentPanel(); add(cp); SearchPanel<Invoice> lf = new SearchPanel<>(Invoice.class); cp.add(lf); lf.setClicked(a -> search(lf.getCriteria())); }
In this case the metadata takes effect, resulting in: