JBoss.orgCommunity Documentation

Chapter 10. Errai UI

10.1. Get started
10.2. Use Errai UI Components
10.2.1. Parts of an Errai UI component
10.2.2. Using a single component instance
10.2.3. Using multiple instances (for iteration)
10.3. Creating your own component
10.3.1. Basic templated bean
10.3.2. Custom template names
10.3.3. Template providers
10.4. Create an HTML template
10.4.1. Using an HTML fragment as a template
10.4.2. Select a fragment from a larger HTML template
10.5. Adding behaviour to your components
10.5.1. Annotate Elements in the template with @DataField
10.5.2. Allowed DataField types
10.5.3. Accessing the root element of a component
10.5.4. Using JsType element wrappers
10.5.5. Injecting JsTypes and Elements that have multiple tag names
10.5.6. 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 (templated bean 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. JS Interop wrapped events on Elements and Widgets
10.7.3. GWT events on Widgets
10.7.4. GWT events on DOM Elements
10.7.5. Native DOM events on Elements
10.8. HTML Form Support
10.8.1. A Login Form that Triggers Browsers' "Remember Password" Feature
10.8.2. Using the Correct Elements in the Template
10.9. Data Binding
10.9.1. Default, Simple, and Chained Property Bindings
10.9.2. Binding of Lists
10.9.3. Data Converters
10.10. Nest components
10.11. Extend components
10.11.1. Template
10.11.2. Parent component
10.11.3. Child component
10.12. Stylesheet binding
10.12.1. Usage with Data Binding
10.13. Internationalization (i18n)
10.13.1. HTML Template Translation
10.13.2. TranslationKey and TranslationService
10.14. 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 components. Inevitably one must turn to Java-based configuration in order to finish the job. In contrast, Errai strives to remove the need for Java styling. HTML template files are placed in the project source tree and referenced from custom Errai UI components 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 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 components:

Plugin Tip

Use the Errai Forge Addon Add Errai Features command and select Errai UI to follow along with this section.

Manual Setup

Checkout the Manual Setup Section for instructions on how to manually add Errai UI to your project. If you work better by playing with a finished product, you can see a simple client-server project implemented using Errai UI here.

Widget-based Components

Since Errai 4.0, Errai UI components are no longer required to extend Composite. In fact, extending Composite is deprecated. Though components can still be built with and as widgets, we encourage users to build components using purely native HTML elements.

As previously mentioned, components in Errai UI consist of a Java class (the templated bean), an HTML file (the template), and an optional CSS file (the template stylesheet). A Java class is a templated bean if the type is 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 component to add behavior, and use additional components to add functionality to the template. There is no limit to how many templated beans may share a given HTML template.

You can also use a full HTML document that is more easily previewed during design. When doing this you must specify the location of the component’s root DOM Element within the template file using a "data-field", id, or class attribute matching the value of the @Templated annotation. There is no limit to how many templated beans may share a single HTML template.

Multiple components may use the same template, specifying any elements as a their root elements. In particular, note that two or more components may declare the same DOM element of this template file as their root elements; there is no conflict because are each components instantiated with a unique copy of the template DOM rooted at the specified element at runtime (or from the root element if a fragment is not specified.)

For example, the component below also uses the same template file by referencing the template name, and specifying a fragment.

@Templated("my-template.html#theme-footer")

public class Footer {
   /* Specifies that <... id="theme-footer"> be used as the root Element of this Widget */
}

Now that we know how to create a @Templated bean 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. We can even replace portions of the template with other Errai UI components!

In order to substitute elements into the template DOM you must annotate fields in your templated bean with @DataField and mark the HTML template element with a correspondingly named data-field, id, or class attribute. All replacements happen while the component is being constructed; thus, fields annotated with @DataField must either be @Injected or manually initialized when the templated bean is instantiated.

/*

* Here the template file is implicitly LoginForm.html.
* The root element has id, class, or data-field "form".
*/
@Templated("#form")
public class LoginForm {
   // This is the root element of the template, for adding this component to the DOM.
   @Inject
   @DataField
   private Form form;
   // If not otherwise specified, the name to match in the HTML template defaults
   // to the name of the field; in this case, the name would be "username"
   @Inject
   @DataField
   private TextInput username;
   // The name to reference in the template can also be specified manually
   @Inject
   @DataField("pass")
   private PasswordInput password;
   // We can also choose to instantiate our own data fields. Injection is not required.
   @DataField
   private Button submit = (Button) Window.getDocument().createElement("button");
}

When programmatically adding components to the DOM, it is necessary to access their HTMLElement roots. Errai UI provides two ways of doing this.

Since 4.0, Errai UI supports working with JS interop wrappers of DOM elements. Additionally, Errai provides a concise way of allowing your custom JS interop wrappers to be injected into components.

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:

@Templated

public class ErroneousTemplate {
   @Inject @DataField
   private Div eat;
   @Inject @DataField
   private Div drink;
}

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 component allows Errai UI to determine where and what should be composited when creating component instances.


<form id="form">
  <legend>Log in to your account</legend>

  <label for="username">Username</label>
  <input id="username" type="text" placeholder="Username">

  <label for="password">Password</label>
  <input data-field="pass" id="password" type="password" placeholder="Password">

  <button id="submit">Log in</button>
  <button>Cancel</button>
</form>

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

Three things are merged or modified when Errai UI creates a new 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:

This approach can be used to handle events on any kind of @DataField or on a data-field element in the HTML template. Since many browser event types share interfaces a quick handler with a JS interop event parameter must sometimes specify the browser event type (i.e. "click", "blur", "focus", etc.).

Here is an example of a quick handler for "click" events on an element @DataField where the Event parameter is a JS interop wrapped event type org.jboss.errai.common.client.dom.Event. The Event interfaces is annotated with @BrowserEvent, but does not specify a value of usable browser event types, so the quick handler must specify the event type is listens to with the @ForEvent annotation.

@Templated

public class ElementHandlerComponent {
   @Inject
   @DataField("b1")
   private ButtonElement button;
   @EventHandler("b1")
   public void doSomething(@ForEvent("click") Event e) {
     // do something
   }
}

For @BrowserEvent wrappers that specify event types, @ForEvent may be omitted. In this case the quick handler is registered for all supported event types. In the example below, FocusEvent is annotated with @BrowserEvent({"blur", "focus", "focusin", "focusout"}), so the quick handler is registered for all four event: blur, focus, focusin, and focusout.

@Templated

public class ElementHandlerComponent {
   @Inject
   @DataField
   private AnchorElement link;
   @EventHandler("link")
   public void doSomething(FocusEvent e) {
     // do something
   }
}

This approach can also be used with GWT Widget @DataFields and template data-fields that do not have a @DataField.

@Templated

public class WidgetAndElementHandlerComponent {
   @Inject
   @DataField
   private TextBox input;
   // Handles focus-related events on the
   // underlying HTML element of the TextBox field.
   @EventHandler("input")
   public void doSomething(FocusEvent e) {
     // do something
   }
   // Handles dblclick events for the element in the
   // template with id/class/data-field="button".
   @EventHandler("button")
   public void onClick(@ForEvent("dblclick") MouseEvent e) {
     // do something
   }
}

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.


<div>
   <a id="link" href="/page">this is a hyperlink</a>
   <div data-field="div"> Some content </div>
</div>

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.

@Templated

public class QuickHandlerComponent extends Composite {
  @DataField
  private AnchorElement link = DOM.createAnchor().cast();
  @EventHandler("link")
  @SinkNative(Event.ONCLICK | Event.ONMOUSEOVER)
  public void doSomething(Event e) {
    // do something
  }
  @EventHandler("div")
  @SinkNative(Event.ONMOUSEOVER)
  public void doSomethingElse(Event e) {
    // do something else
  }
}

Using asynchronous Javascript calls often make realizing the benefits of modern browsers difficult when it comes to form submission. But there is now a base class in Errai UI for creating @Templated form widgets that are perfect for tasks such as creating a login form.

Here is a sample @Templated login form class. This form has:

@Dependent

@Templated
public class LoginForm extends AbstractForm { 
1
  @Inject
  private Caller<AuthenticationService> authenticationServiceCaller;
  @Inject
  @DataField
  private TextBox username;
  @Inject
  @DataField
  private PasswordTextBox password;
  @DataField
  private final FormElement form = DOM.createForm(); 
2
  @Inject
  @DataField
  private Button login; 
3
  @Override
  protected FormElement getFormElement() {
    return form; 
4
  }
  @EventHandler("login")
  private void loginClicked(ClickEvent event) {
    authenticationServiceCaller.call(new RemoteCallback<User>() {
      @Override
      public void callback(User response) {
        // Now that we're logged in, submit the form
        submit(); 
5
      }
    }).login(username.getText(), password.getText());
  }
}

The key things that you should take from this example:

1

The class extends org.jboss.errai.ui.client.widget.AbstractForm.

2

The form field is a @DataField but it is not injected.

3

The login button is a regular button widget, with a click handling method below.

4

The getFormElement method inherited from AbstractForm must return the FormElement that will be submitted.

5

After the user has successfully logged in asynchronously we call submit(). This causes form submission to happen in a way that will not cause the page to refresh, but will still properly notify the browser of a form submission.

When a user successfully logs in via this example, the web browser should prompt them to remember the username and password (assuming this is a feature of the browser being used).

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 {
   @Inject
   @Model
   private User user;
   @Inject
   @Bound
   @DataField
   private InputElement 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:

@Bindable

public class Address {
  private String line1;
  private String line2;
  private String city;
  private String stateProv;
  private String country;
  // getters and setters
}
@Bindable
public class User {
  private String name;
  private String password;
  private Date dob;
  private Address address;
  private List<Role> roles;
  // getters and setters
}
@Templated
public class UserComponent {
  @Inject @AutoBound DataBinder<User> user;
  @Inject @Bound InputElement name;
  @Inject @Bound(property="dob") DatePicker dateOfBirth;
  @Inject @Bound(property="address.city") TextBox city;
}

In UserComponent above, the name input element 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 component. This task can be accomplished using Errai UI’s ListWidget class. Here’s an example of binding a list of users using the UserComponent class from the previous example. First, we need to enhance UserComponent to implement HasModel.

@Templated

public class UserWidget implements HasModel<User> {
  @Inject @AutoBound DataBinder<User> userBinder;
  @Inject @Bound InputElement name;
  @Inject @Bound(property="dob") DatePicker dateOfBirth;
  @Inject @Bound(property="address.city") TextBox city;
  public User getModel() {
    userBinder.getModel();
  }
  public void setModel(User user) {
    userBinder.setModel(user);
  }
}

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

@Templated

public class MyComponent {
  @Inject @DataField ListWidget<User, UserComponent> userListWidget;
  @PostConstruct
  public void init() {
    List<User> users = .....
    userListWidget.setItems(users);
  }
}

Calling setItems on the userListWidget causes an instance of UserComponent to be displayed for each user in the list. The UserComponent 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.

public class UserListWidget extends ListWidget<User, UserWidget> {


  public UserList() {
    super(new HorizontalPanel());
  }
  @PostConstruct
  public void init() {
    List<User> users = .....
    setItems(users);
  }
  @Override
  public Class<UserWidget> getItemWidgetType() {
    return UserWidget.class;
  }
}

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 components to build up a hierarchy of UI componenets functions exactly the same as when building hierarchies of GWT widgets or DOM elements. The only distinction might be that with Errai UI, @Inject is preferred to manual instantiation.

@Templated

public class ComponentOne {
   @Inject
   @DataField("other-comp")
   private ComponentTwo two;
}

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 components extending from a parent 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. One common case is 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.

@StyleBinding

@Retention(RetentionPolicy.RUNTIME)
public @interface Admin {
}

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

@EntryPoint

@Templated
public class HelloWorldForm {
  @Inject @Admin @DataField ButtonElement deleteButton;
  @Inject SessionManager sessionManager;
  @EventHandler("deleteButton")
  private void handleSendClick(ClickEvent event) {
    // do some deleting!
  }
  @Admin
  private void applyAdminStyling(Style style) {
    if (!sessionManager.isAdmin()) {
      style.setVisibility(Style.Visibility.HIDDEN);
    }
  }
}

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.

The above example took at Style object as a parameter, but it is also possible to use an Element. So the applyAdminStyling method above could have also been written like this:

  @Admin

  private void applyAdminStyling(Element element) {
    if (!sessionManager.isAdmin()) {
      element.addClassName("disabled");
    }
  }

The CSS class "disabled" could apply the same style as before ("visibility: hidden") or it could have more complex behaviour that is dependent on the element type.

User interfaces often need to be available in different languages. Errai’s i18n support makes it easier for you to publish your web app in multiple languages. This section explains how to use this feature in your application.

To get started with Errai’s internationalization support, simply put @Bundle("bundle.json") or @Bundle("bundle.properties") annotation on your entry point and add an empty bundle.json or bundle.properties file to your classpath (e.g. to src/main/java or src/main/resources). Of course, you can name it differently provided the file extension is .json or .properties.

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. If you used a JSON file in you @Bundle annotation, 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 or bundel_nl_BE.properties for Belgian Dutch, and bundle_nl.json or bundle_nl.properties 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 when you use a JSON file:

{
"StoresPage.Stores!" : "Stores!",
"WelcomePage.As_you_move_toward_a_more_and_more_declarative_style,_you_allow_the_compiler_and_the_framework_to_catch_more_mistakes_up_front._-734987445" : "As you move toward a more and more declarative style, you allow the compiler and the framework to catch more mistakes up front. Broken links? A thing of the past!"
}

Here are the same translations as specified by a properties file:

StoresPage.Stores! = Stores!
WelcomePage.As_you_move_toward_a_more_and_more_declarative_style,_you_allow_the_compiler_and_the_framework_to_catch_more_mistakes_up_front._-734987445 = As you move toward a more and more declarative style, you allow the compiler and the framework to catch more mistakes up front. Broken links? A thing of the past!

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:


<html>
<body>
  <div id="content">
  <p data-i18n-key="welcome">Welcome to errai-ui i18n.</p>
<div>
...

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

{
    "TemplatedClassName.welcome": "Willkommen bei Errai-ui i18n."
}

or

TemplatedClassName.welcome=Willkommen bei Errai-ui i18n.

These keys are prefixed with the name of the @Templated class to which they belong, and as such will only applied to the element with data-i18n-key="welcome" in that classes template. You may also declare translations without the prefix that can apply to any template, like so:

{
    "welcome": "Willkommen bei Errai-ui i18n."
}

or

welcome=Willkommen bei Errai-ui i18n.

Either of these translations will apply to elements with data-i18n-key="welcome" in any template.

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:


<div id=navbar data-role=dummy>
  <div class="navbar navbar-fixed-top">
    <div class=navbar-inner>
      <div class=container>
        <span class=brand>Example Navbar</span>
        <ul class=nav>
          <li><a>Item</a>
          <li><a>Item</a>
        </ul>
      </div>
    </div>
  </div>
</div>

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:

@Templated

public class NavBar {
  @Inject
  private LocaleSelector selector;
  @Inject @DataField @OrderedList
  ListWidget<Locale, LanguageItem> language;
  @AfterInitialization
  public void buildLanguageList() {
    language.setItems(new ArrayList<Locale>(selector.getSupportedLocales()));
  }
...
// in LanguageItem we add a click handler on a link
  @Inject
  Navigation navigation;
  @Inject
  private LocaleSelector selector;
  link.addClickHandler(new ClickHandler() {
      @Override
      public void onClick(ClickEvent event) {
        selector.select(model.getLocale());
        navigation.goTo(navigation.getCurrentPage().name());
      }
    });

The @TranslationKey annotation and TranslationService class extend Errai’s i18n support to Java code. They provide a mechanism for developers to declare translation strings from within their GWT application code (as opposed to the HTML templates).

To do this, developers must annotate a field which represents the translation key with @TranslationKey annotation. This key will then map to a value in the translation bundle file. Once the field is annotated appropriately, the developer must directly invoke the TranslationService’s format() method. This method call will perform a lookup in the translation service of the value mapped to the provided key. Note that value substitution using the {N} format is supported.

As an example, consider the following code:

package org.example.ui.client.local;


public class AppMessages {
   @TranslationKey(defaultValue = "I guess something happened!")
   public static final String CUSTOM_MESSAGE = "app.custom-message";
   @TranslationKey(defaultValue = "Hey {0}, I just told you something happened!")
   public static final String CUSTOM_MESSAGE_WITH_NAME = "app.custom-message-with-name";
}
package org.example.ui.client.local;


@Dependent
@Templated
public class CustomComponent extends Composite {
   @Inject
   private TranslationService translationService;
   @Inject
   @DataField
   private Button someAction;
   @EventHandler("someAction")
   private void doLogin(ClickEvent event) {
      // do some action that may require a notification sent to the user
      String messageToUser = translationService.format(AppMessages.CUSTOM_MESSAGE);
      Window.alert(messageToUser);
      String username = getCurrentUserName();
      String messageToUserWithName = translationService.format(AppMessages.CUSTOM_MESSAGE_WITH_NAME, username);
      Window.alert(messageToUserWithName);
   }
}

Errai also supports LESS stylesheets for @Templated. You can specify a CSS or LESS stylesheet path for a component with the stylesheet attribute of @Templated, as in the example below:

package org.jboss.errai.example;


@Templated(stylesheet = "main.less")
public class StyledComponent {
}

For the above example, during GWT compilation Errai will load the LESS stylesheet from the classpath (in this case with the path org/jboss/errai/example/main.less) and compile it. At runtime the compiled CSS will be loaded.

You can omit the stylesheet attribute if your LESS stylsheet follows the standard Errai UI naming conventions. For example:

package org.jboss.errai.example;


@Templated
public class StyledComponent {
}

Errai will automatically find and compile a LESS stylesheet for this template if it exists on the classpath at this path: org/jboss/errai/example/StyledComponent.less

Precedence of CSS and LESS

When the stylesheet attribute is not specified, Errai will only find a LESS stylesheet as described above if no CSS stylesheet exists at the default path.