DomUI components use data binding to easily move data from the UI component to any underlying data model. Data binding makes it possible (and relatively easy) to separate the code for UI and business by using MVC or MVVC like patterns. Using data binding decouples the UI from the logic, and makes it possible to test the logic using normal JUnit tests instead of having to write Selenium like UI tests.
Data binding example
Before we go into a long monologue about how Data Binding works - let's look at few examples. We will use the Demo application's database and create a screen to edit an Invoice. This is done using the following code:
public class EditInvoicePageB1 extends UrlPage { private Invoice m_invoice; @Override public void createContent() throws Exception { ContentPanel cp = new ContentPanel(); add(cp); //-- Default invoice fields if(null == m_invoice.getInvoiceDate()) m_invoice.setInvoiceDate(new Date()); //-- Manually create a form layout for educational pps - usually this is done using FormBuilder. TBody tb = cp.addTable(); tb.addCssClass("ui-tbl-spaced"); LookupInput2<Customer> custLI = new LookupInput2<Customer>(QCriteria.create(Customer.class)); tb.addRowAndCell().add(new Label(custLI, "Customer")); tb.addCell().add(custLI); DateInput2 dateC = new DateInput2(); tb.addRowAndCell().add(new Label(dateC, "Invoice Date")); tb.addCell().add(dateC); TextStr addrC = new TextStr(); tb.addRowAndCell().add(new Label(addrC, "Address")); tb.addCell().add(addrC); Text<BigDecimal> amountC = new Text<>(BigDecimal.class); tb.addRowAndCell().add(new Label(amountC, "Amount")); tb.addCell().add(amountC); } @UIUrlParameter(name = "invoice") public Invoice getInvoice() { return m_invoice; } public void setInvoice(Invoice invoice) { m_invoice = invoice; } }
If we open this screen using the url http://localhost:8088/demo/to.etc.domuidemo.pages.binding.tut1.EditInvoicePage.ui?invoice=2 this will show a screen like this:
The controls are there but the data is not. To do that we would normally code things like:
customerLI.setValue(m_invoice.getCustomer()); dateC.setValue(m_invoice.getInvoiceDate()); // and so on, for all controls.
What is worse- we have to repeat this - or the reverse order (from components back to the Invoice instance) every time we want the data there. This is tedious and error prone.
So instead we will use data binding. We add the following at the end of createContext():
custLI.bind().to(m_invoice, "customer"); dateC.bind().to(m_invoice, "invoiceDate"); addrC.bind().to(m_invoice, "billingAddress"); amountC.bind().to(m_invoice, "total");
and we now have the following screen (live):