Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Simple Everyday Tips for Vaadin Developers (Part 4: Data Modeling)

DZone's Guide to

Simple Everyday Tips for Vaadin Developers (Part 4: Data Modeling)

The fourth part of a five parts series about tips for Vaadin developers, this article discusses data modeling and binding within the Vaadin framework.

· Java Zone
Free Resource

Download Microservices for Java Developers: A hands-on introduction to frameworks and containers. Brought to you in partnership with Red Hat.

This is the fourth part of a five parts series about tips for Vaadin developers. Here are all the series parts:

  1. Migrating From Vaadin 6 to Vaadin 7
  2. UI abstraction and using Vaadin CDI Add-on
  3. Styling Vaadin components and using Add-ons
  4. Data modeling in Vaadin
  5. Simple use case for Vaadin Grid

4. Data Modeling in Vaadin

Image title

Dealing with data in a UI framework is usually challenging; luckily Vaadin has a set of tools that helps data binding using Java standards. If you ever found yourself manually binding data with a component, always remember that there is an alternative, easier, and more reliable way.

In our demo, checkboxes were added manually. One item at a time. There is a nicer way in Vaadin to automagically generate checkboxes: the OptionGroup.

Replace:

for (Product product : productService.getProducts()) {
  CheckBox cb = new CheckBox(product.getName() " ("
  df.format(product.getPrice()) ")");
  cb.setData(product);
}


With:

OptionGroup options = new OptionGroup();
options.setMultiSelect(true);


Now our OptionGroup will automatically, after given a container, display the data as checkboxes. That’s why I used GeneratedPropertyContainer with customized caption generation:

GeneratedPropertyContainer gContainer = new GeneratedPropertyContainer(
    new IndexedContainer(productService.getProducts()));

gContainer.addGeneratedProperty(CAPTION_PROPERTY,
    new PropertyValueGenerator<String>() {

  @Override
  public String getValue(Item item, Object itemId, Object propertyId) {
    Product product = (Product) itemId;
    return product.getName() " (" + formatPrice(product.getPrice()) ")";
  }

  @Override
  public Class<String> getType() {
    return String.class;
  }
});

options.setContainerDataSource(gContainer);


In our container now there is a new property called CAPTION_PROPERTY, to make this property the displayed caption on each checkbox:

options.setItemCaptionPropertyId(CAPTION_PROPERTY);
Related commit: Add better data model for checkboxes


Similarly, the labels displaying the product price, shipping, and promotions can be automatically bound with a datasource. We can use the BeanFieldGroup, but the issue here is that Label is not a Field. It’s not a blocker issue though; there are a lot of ideas discussed in the forums like using a readonly TextField and style it to look like a label. Or by manually changing the property value of the Label. We can also create a custom Field that uses Label as the base component, and luckily there is already an add-on for that! Viritin is a powerful add-on that solves many corner cases like ours here. It has a LabelField component that does exactly what we need—a Label that can be bound to a BeanFieldGroup.

Dependency in Maven is all we need to get this add-on in our classpath:

<dependency>
  <groupId>org.vaadin</groupId>
  <artifactId>viritin</artifactId>
  <version>1.39</version>
</dependency>


But back to the original topic. We want labels to be automatically populated with data once the underlying datasource values change, without manually doing so. BeanFieldGroup is our best friend; here is how to use it:

First let’s convert Label into LabelField by removing this:

private Label subtotalValue = new Label();
private Label cartPromoValue = new Label();
private Label shippingValue = new Label();
private Label shippingPromoValue = new Label();
private Label cartTotalValue = new Label();


And replacing with:

@PropertyId("cartItemTotal")
private LabelField<String> subtotalValue = new LabelField<String>();

@PropertyId("cartItemPromoSavings")
private LabelField<String> cartPromoValue = new LabelField<String>();

@PropertyId("shippingTotal")
private LabelField<String> shippingValue = new LabelField<String>();

@PropertyId("shippingPromoSavings")
private LabelField<String> shippingPromoValue = new LabelField<String>();

@PropertyId("cartTotal")
private LabelField<String> cartTotalValue = new LabelField<String>();


The PropertyId annotation is used by BeanFieldGroup to map the field component to its corresponding property, and here is how we define it:

BeanFieldGroup.bindFieldsUnbuffered(sc, this);


And that’s pretty much all! The property "cartItemTotal" in ShoppingCart will be automatically bound to the subtotalValue LabelField, "shippingTotal" to shippingValue, and so on. Data binding with UI can never be easier :-)

Related commit: Add better data model for ShoppingCart properties


It’s often when dealing with data modeling that you'll run into custom property generators, formatters, and converters. I placed them all in external classes so that they can be reused across the project. In this project I used DoubleStringConverter along with a helper Formatter to automatically convert the price amount given in double, to a string with currency placed next to the value. Also StringPropertyValueGenerator was found very useful later on in the Grid as well (discussed in part five). It’s very simple, a PropertyValueGenerator of type String. Having this class is worth it because it prevents code redundancy.

Related commit: Add generalized StringPropertyValueGenerator


It’s getting more and more solid. Did you notice that the “Checkout” button does absolutely nothing in this demo so far? Let’s make the button do something when clicked. That’s what we will discuss in the next and final part of the article, coming soon.

Download Building Reactive Microservices in Java: Asynchronous and Event-Based Application Design. Brought to you in partnership with Red Hat

Topics:
vaadin ,java ,cdi ,ui ,ux ,brms ,jboss

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}