JBoss.orgCommunity Documentation

Chapter 10. Errai UI

10.1. Get started
10.1.1. App.gwt.xml
10.1.2. pom.xml
10.1.3. Working Demo
10.2. Use Errai UI Composite components
10.2.1. Inject a single instance
10.2.2. Inject multiple instances (for iteration)
10.3. Create a @Templated Composite component
10.3.1. Basic component
10.3.2. Custom template names
10.4. Create an HTML template
10.4.1. Select a template from a larger HTML file
10.5. Use other Widgets in a composite component
10.5.1. Annotate Widgets in the template with @DataField
10.5.2. Add corresponding attributes to the HTML template
10.6. How HTML templates are merged with Components
10.6.1. Example
10.6.2. Element attributes (template wins)
10.6.3. DOM Elements (component field wins)
10.6.4. Inner text and inner HTML (preserved when component implements HasText or HasHTML)
10.7. Event handlers
10.7.1. Concepts
10.7.2. GWT events on Widgets
10.7.3. GWT events on DOM Elements
10.7.4. Native DOM events on Elements
10.8. Data Binding
10.8.1. Default, Simple, and Chained Property Bindings
10.8.2. Binding of Lists
10.8.3. Data Converters
10.9. Nest Composite components
10.10. Extend Composite components
10.10.1. Template
10.10.2. Parent component
10.10.3. Child component
10.11. Stylesheet binding
10.12. Internationalization (i18n)
10.13. Extended styling with LESS

One of the primary complaints of GWT to date has been that it is difficult to use "pure HTML" when building and skinning widgets. Inevitably one must turn to Java-based configuration in order to finish the job. Errai, however, strives to remove the need for Java styling. HTML template files are placed in the project source tree, and referenced from custom "Composite components" (Errai UI Widgets) in Java. Since Errai UI depends on Errai IOC and Errai CDI, dependency injection is supported in all custom components. Errai UI provides rapid prototyping and HTML5 templating for GWT.

The Errai UI module is directly integrated with Chapter 9, Data Binding and Errai JPA but can also be used as a standalone project in any GWT client application by simply inheriting the Errai UI GWT module, and ensuring that you have properly using Errai CDI's @Inject to instantiate your widgets:

Before explaining how to create Errai UI components, it should be noted that these components behave no differently from any other GWT Widget once built. The primary difference is in A) their construction, and B) their instantiation. As with most other features of Errai, dependency injection with CDI is the programming model of choice, so when interacting with components defined using Errai UI, you should always @Inject references to your Composite components.

Custom components in Errai UI are single classes extending from com.google.gwt.user.client.ui.Composite , and must be annotated with @Templated.

Templates in Errai UI may be designed either as an HTML snippet or as a full HTML document. You can even take an existing HTML page and use it as a template. With either approach, the id , class , and data-field attributes in the template identify elements by name. These elements and their children are used in the Composite component to add behavior, and use additional components to add functionality to the template. There is no limit to how many component classes may share a given HTML template.

We will begin by creating a simple HTML login form to accompany our @Templated LoginForm composite component.

Or as a full HTML document which may be more easily previewed during design without running the application; however, in this case we must also specify the location of our component's root DOM Element using a "data-field" , id , or class attribute matching the value of the @Templated annotation. There is no limit to how many component classes may share a given HTML template.

Notice the corresponding HTML id attribute in the form Element below (we could have used data-field or class instead). Note that multiple components may use the same template provided that they specify a corresponding data-field , id , or class attribute. Also note that two or more components may share the same DOM elements; there is no conflict since components each receive a unique copy of the template DOM rooted at the designated element at runtime (or from the root element if a fragment is not specified.)

For example's sake, the component below could also use the same template. All it needs to do is reference the template name, and specify a fragment.

Now that we have created the @Templated Composite component and an HTML template, we can start wiring in functionality and behavior; this is done by annotating fields and methods to replace specific sub-elements of the template DOM with other Widgets. We can even replace portions of the template with other Errai UI Widgets!

Each @DataField reference in the Java class must match an element in the HTML template. The matching of Java references to HTML elements is performed as follows:

If more than one Java reference matches the same HTML element in the template, it is an error. For example, given a template containing the element <div class="eat drink be-merry"> , the following Java code is in error:

because both fields eat and drink refer to the same HTML div element.

So now we must ensure there are data-field , id , or class attributes in the right places in our template HTML file. This, combined with the @DataField annotation in our Composite component allow Errai UI to determine where and what should be composited when creating component instances.

Now, when we run our application, we will be able to interact with these fields in our Widget.

Three things are merged or modified when Errai UI creates a new Composite component instance:

Dealing with User and DOM Events is a reality in rich web development, and Errai UI provides several approaches for dealing with all types of browser events using its "quick handler" functionality. It is possible to handle:

The last approach is handles the case where native DOM events must be handled, but no such GWT event handler exists for the given event type. Alternatively, it can also be used for situations where Elements in the template should receive events, but no handle to the Element the component class is necessary (aside from the event handling itself.) Native DOM events do not require a corresponding @DataField be configured in the class; only the HTML data-field , id , or class template attribute is required.

The @SinkNative annotation specifies (as a bit mask) which native events the method should handle; this sink behaves the same in Errai UI as it would with DOM.sinkEvents(Element e, int bits) . Note that a @DataField reference in the component class is optional.

A recurring implementation task in rich web development is writing event handler code for updating model objects to reflect input field changes in the user interface. The requirement to update user interface fields in response to changed model values is just as common. These tasks require a significant amount of boilerplate code which can be alleviated by Errai. Errai's data binding module provides the ability to bind model objects to user interface fields, so they will automatically be kept in sync. While the module can be used on its own, it can cut even more boilerplate when used together with Errai UI.

In the following example, all @DataFields annotated with @Bound have their contents bound to properties of the data model (a User object). The model object is injected and annotated with @Model , which indicates automatic binding should be carried out. Alternatively, the model object could be provided by an injected DataBinder instance annotated with @AutoBound , see Declarative Binding for details.



@Templated
public class LoginForm extends Composite {
   @Inject
   @Model
   private User user;
   @Inject
   @Bound
   @DataField
   private TextBox name;
   @Inject
   @Bound
   @DataField
   private PasswordTextBox password;
   @DataField
   private Button submit = new Button();
}

Now the user object and the username and password fields in the UI are automatically kept in sync. No event handling code needs to be written to update the user object in response to input field changes and no code needs to be written to update the UI fields when the model object changes. So, with the above annotations in place, it will always be true that user.getUsername().equals(username.getText()) and user.getPassword().equals(password.getText()) .

By default, bindings are determined by matching field names to property names on the model object. In the example above, the field name was automatically bound to the JavaBeans property name of the model ( user object). If the field name does not match the model property name, you can use the property attribute of the @Bound annotation to specify the name of the property. The property can be a simple name (for example, "name") or a property chain (for example, user.address.streetName ). When binding to a property chain, all properties but the last in the chain must refer to @Bindable values.

The following example illustrates all three scenarios:

In UserWidget above, the name text box is bound to user.name using the default name matching; the dateOfBirth date picker is bound to user.dob using a simple property name mapping; finally, the city text box is bound to user.address.city using a property chain. Note that the Address class is required to be @Bindable in this case.

Often you will need to bind a list of model objects so that every object in the list is bound to a corresponding widget. This task can be accomplished using Errai UI's ListWidget class. Here's an example of binding a list of users using the UserWidget class from the previous example. First, we need to enhance UserWidget to implement HasModel .

Now we can use UserWidget to display items in a list.

Calling setItems on the userListWidget causes an instance of UserWidget to be displayed for each user in the list. The UserWidget is then bound to the corresponding user object. By default, the widgets are arranged in a vertical panel. However, ListWidget can also be subclassed to provide alternative behaviour. In the following example, we use a horizontal panel to display the widgets.

The @Bound annotation further allows to specify a converter to use for the binding (see Specifying Converters for details). This is how a binding specific converter can be specified on a data field:



@Inject
@Bound(converter=MyDateConverter.class)
@DataField
private TextBox date;

Errai's DataBinder also allows to register PropertyChangeHandlers for the cases where keeping the model and UI in sync is not enough and additional logic needs to be executed (see Property Change Handlers for details).

Using Composite components to build up a hierarchy of widgets functions exactly the same as when building hierarchies of GWT widgets. The only distinction might be that with Errai UI, @Inject is preferred to manual instantiation.

Templating would not be complete without the ability to inherit from parent templates, and Errai UI also makes this possible using simple Java inheritance. The only additional requirement is that Composite components extending from a parent Composite component must also be annotated with @Templated, and the path to the template file must also be specified in the child component's annotation. Child components may specify @DataField references that were omitted in the parent class, and they may also override @DataField references (by using the same data-field name) that were already specified in the parent component.

When developing moderately-complex web applications with Errai, you may find yourself needing to do quite a bit of programmatic style changes. A common case being: showing or enabling controls only if a user has the necessary permissions to use them. One part of the problem is securing those features from being used, and the other part – which is an important usability consideration – is communicating that state to the user.

Let's start with the example case I just described. We have a control that we only want to be visible if the user is an admin. So the first thing we do is create a style binding annotation.

This defines Admin as a stylebinding now we can use it like this:

Now before the form is shown to the user the applyAdminStyling method will be executed where the sessionManager is queried to see if the user is an admin if not the delete button that is also annotated with @Admin will be hidden from the view.

In addition when using this in conjunction with Errai Databinding. Any Errai UI component which uses @AutoBound, will get live updating of the style rules for free, anytime the model changes. Allowing dynamic styling based on user input and other state changes.

User interfaces often need to be available in multiple languages. To get started with Errai's internationalization support, simply put the @Bundle("bundle.json") annotation on your entry point and add an empty bundle.json file to your classpath (e.g. to src/main/java or src/main/resources). Of course, you can name it differently.

Errai will scan your HTML templates and process all text elements to generate key/value pairs for translation. It will generate a file called errai-bundle-all.json and put it in your .errai directory. You can copy this generated file and use it as a starting point for your custom translation bundles. If the text value is longer than 128 characters the key will get cut off and a hash appended at the end.

The translation bundle files use the same naming scheme as Java (e.g. bundle_nl_BE.json for Belgian Dutch and bundle_nl.json for plain Dutch). Errai will also generate a file called errai-bundle-missing.json in the .errai folder containing all template values for which no translations have been defined. You can copy the key/value pairs out of this file to create our own translations:

If you want to use your own keys instead of these generated ones you can specify them in your templates using the data-i18n-key attribute:

By adding this attribute in the template you can translate it with the following:

Because your templates are designer templates and can contain some mock data that doesn't need to be translated, Errai has the ability to indicate that with an attribute data-role=dummy :

Here the template fills out a navbar with dummy elements, useful for creating a design, adding data-role=dummy will not only exclude it form being translated it will also strip the children nodes from the template that will be used by the application.

When you have setup a translation of your application Errai will look at the browser locale and select the locale, if it's available, if not it will use the default ( bundle.json ). If the users of your application need to be able to switch the language manually, Errai offers a pre build component you can easily add to your page: LocaleListBox will render a Listbox with all available languages. If you want more control of what this language selector looks like there is also a LocaleSelector that you can use to query and select the locale for example:

Errai also supports LESS stylesheets. To get started using these you'll have to create a LESS stylesheet and place it on the classpath of your project. Errai will convert the LESS stylesheet to css preform optimisations on it and ensure that is get injected into the pages of your application. It will also obfuscate the class selectors and replace the use of those in your templates. To be able to use the selectors in your code you can use:



public class MyComponent extends Component {
� �@Inject
� �private LessStyle lessStyle;
...
� �@PostCreate
� �private void init() {
� � � �textBox.setStyleName(lessStyle.get("input"));
� �}
}

Finally it will also add any deferred binding properties to the top of your LESS stylesheet, so for example you could use the user.agent in LESS like this:



.mixin (@a) when (@a = "safari") {
  background-color: black;
}
.mixin (@a) when (@a = "gecko1_8") {
  background-color: white;
}
.class1 { .mixin(@user_agent) }

Because a dot is not allowed in LESS variables it's replaced with an underscore, so in the example above class1 will have a black background on Safari and Chrome and white on Firefox. On the top of this LESS stylesheet @user_agent: "safari" will get generated.