Creating a Simple Component Using the Template API

There are multiple ways you can create a component. This tutorial uses the PolymerTemplate API with no additional elements or components. For other component tutorials, see:

For tutorials about how to use different template features, see:

This tutorial is based on the Hello Worlds technical demo. The demo shows three ways of achieving the same result: using components, element API and the template approach.

We’ll create a demo, that will be asking a user to input a name and will print a greeting on button click, using the input.

Client side

First, we need to define a template with all components:

<link rel="import" href="../bower_components/polymer/polymer-element.html">
<link rel="import" href="../bower_components/paper-input/paper-input.html">

<dom-module id="hello-world">
    <template>
        <div>
            <paper-input id="inputId" value="{{userInput}}"></paper-input>
            <button id="helloButton" on-click="sayHello">Say hello</button>
            <div id="greeting">[[greeting]]</div>
        </div>
    </template>
    <script>
        class HelloWorld extends Polymer.Element {
            static get is() {
                return 'hello-world'
            }
        }
        customElements.define(HelloWorld.is, HelloWorld);
    </script>
</dom-module>

As you can see, this is a Polymer template. All features used in the example are standard Polymer features. If you’re unfamiliar with any of them, please refer to Polymer project documentation page.

Note
The tag name of the template, which is defined by the id attribute on the <dom-module> element and the return of the function is(), should have at least one dash (-). The value hello-world is a valid tag name, but helloworld is not.

In the current demo, we have defined a regular template with regular elements, have specified one-way binding ([[greeting]]), two-way binding ({{userInput}}) and basic declaration for Polymer element in <script> class.

Note that there is an event handler sayHello that is triggered on helloButton click.

Notice that we have not specified the model at all, it will be propagated automatically from the server side.

We’ve also imported some dependencies:

  • Polymer library

The ../bower_components/polymer/polymer-element.html is a link to Polymer library that should be imported in order to have the functionality working.

Note
You should take care about proper handling of the Polymer template file URL, it should be available via URL.
Note
To get polymer-element.html into your project, you can use one of the ways provided by official Polymer page or use Maven plugins, such as frontend-maven-plugin

The latter way was used to create this example, you can reference GitHub page of a demo for more details.

  • paper-input Polymer component

For clarity and demonstration purposes, this example uses paper-input.html component.

Note
In order to retrieve and use the component in the demo, same rules as for polymer-element.html apply.

Server side

To be able to use this template you need to create a Java class which extends PolymerTemplate, set its tag name matching the Polymer dom-module id attribute and add the html imports for Polymer library (polymer-element.html) and our template:

@Tag("hello-world")
@HtmlImport("/src/HelloWorld.html")
public class HelloWorld extends PolymerTemplate<HelloWorldModel> {
    private static final String EMPTY_NAME_GREETING = "Please enter your name";

    /**
     * Creates the hello world template.
     */
    public HelloWorld() {
        setId("template");
        getModel().setGreeting(EMPTY_NAME_GREETING);
    }

    @EventHandler
    private void sayHello() {
        // Called from the template click handler
        getModel().setGreeting(Optional.ofNullable(getModel().getUserInput())
                .filter(userInput -> !userInput.isEmpty())
                .map(greeting -> String.format("Hello %s!", greeting))
                .orElse(EMPTY_NAME_GREETING));
    }
}

Here we have defined a class with imports, tag, model and event handler.

There is also a model reference, that is defined the following way:

/**
 * Model for the template.
 */
public interface HelloWorldModel extends TemplateModel {
    /**
     * Gets user input from corresponding template page.
     *
     * @return user input string
     */
    String getUserInput();

    /**
     * Sets greeting that is displayed in corresponding template page.
     *
     * @param greeting
     *            greeting string
     */
    void setGreeting(String greeting);
}
Imports

In order for a component to be processed correctly, we need to bind a Java class with the template, created earlier, by specifying @HtmlImport with path to a template

Note
Java class name and template file name doesn’t have to match each other, this is just a resource file which you can put to any location. But you have to be sure that it’s accessible via the web.

The /src/HelloWorld.html is the URL of the Polymer template file declared earlier.

If needed, more html resources can be imported using the same approach.

Tag

The tag corresponds to <dom-module id="hello-world"> id attribute, it sets the tag value to current component.

Model

Model describes all properties that are passed to the html template and used on the client side. The model is simple Java interface, extending TemplateModel class and having getter and/or setter methods for properties. Model can be accessed via getModel() method after it’s specified as a generic type of PolymerTemplate class.

Event handler

Server side has method, annotated with @EventHandler annotation, that is used to react on event form the client side, triggered by the helloButton button.

Call the server side method from the client side

Another way to call a server side method is @ClientCallable annotation which marks a template method as the method which should be called from the client side code using notation this.$server.serverMethodName(args). It can be used somewhere in your client side Polymer class implementation. You can pass your own arguments in this method. Just make sure that their types matches to method declaration on the server side.

Receiving "after server update" event

In some cases you may want to execute some client-side logic after the component is updated from the server during a roundtrip. E.g. the component constructor is called to create a component on the client side but this component is not yet initialized by data from the server side. So it’s too early to do anything with the component which is not yet ready. In this case you can use the method afterServerUpdate. If this method is defined for the component it will be called each time after the component is updated from the server side.

<link rel="import" href="../bower_components/polymer/polymer-element.html">

<dom-module id="my-component">
    <template>
        <div>
            <div>[[text]]</div>
        </div>
    </template>
    <script>
        class MyComponent extends Polymer.Element {
            static get is() {
                return 'my-component'
            }

            afterServerUpdate(){
                console.log("The new 'text' value is: "+this.text);
            }
        }
        customElements.define(MyComponent.is, MyComponent);
    </script>
</dom-module>

Usage in code

You can use HelloWorld like any other component.

HelloWorld hello = new HelloWorld();

Div layout = new Div();
layout.add(hello);
Note
To make your template-based product supporting non-ES6 browers like IE 11 and Safari 9, you need to configure the vaadin-maven-plugin in your pom.xml. See the chapter Taking your Application into Production for more information.