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

Learn how to troubleshoot and diagnose some of the most common performance issues in Java today. Brought to you in partnership with AppDynamics.

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.

Understand the needs and benefits around implementing the right monitoring solution for a growing containerized market. Brought to you in partnership with AppDynamics.

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

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

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

{{ parent.tldr }}

{{ parent.urlSource.name }}