Handling User Events in Polymer Templates
Note
|
Use Lit templates instead
Lit templates are recommended. Polymer templates are available in the next long term supported Vaadin version (LTS), but they are deprecated.
|
Defining Client-side Event Handlers
PolymerTemplate
defines special syntax to attach client-side event handlers to elements. Use the on-eventname="methodName"
syntax to define the handler. Note that the method name should not have any arguments or parenthesis.
Example: Defining an event handler in the EventhandlerDemo
JavaScript Polymer template.
class EventhandlerDemo extends PolymerElement {
static get template() {
return html`<button on-click="handleClick">Say hello</button>`;
}
static get is() {return 'eventhandler-demo'}
handleClick() {
console.log('Button was clicked.');
window.alert('Hello');
}
}
customElements.define(XCustom.is, XCustom);
-
This defines a
<button>
click that displays an alert in the browser.
You can use the on-eventname
syntax to listen to both built-in browser events and custom events, for example from a Web Component. You can typically find the available events in the component documentation.
Handling Events on the Server side
You can use the @EventHandler
annotation to handle DOM events defined in a Polymer template.
Example: Defining the handleClick
method in a JavaScript Polymer template.
class EventHandler extends PolymerElement {
static get template() {
return html`<button on-click="handleClick">Click me</button>`;
}
static get is() { return 'event-handler' }
}
customElements.define(EventHandler.is, EventHandler);
Example: Using the @EventHandler
annotation to reference the handleClick
method.
@Tag("event-handler")
@JsModule("./com/example/event-handler.js")
public class EventHandlerPolymerTemplate extends PolymerTemplate<TemplateModel> {
@EventHandler
private void handleClick() {
System.out.println("Received a handle click event");
}
}
-
When you add the
@EventHandler
annotation on thehandleClick()
method, Vaadin automatically connects the handler to the client-side event .
Note
| If you add both client and server-side event listeners, the client-side handlers are called before the server-side handlers. |
Adding Event Data to Server-side Events
An event can include additional information about what occurred, for example the mouse button used for a click event. When you use the @EventHandler
annotation, you can define an @EventData
annotation for each method parameter. This annotation tells Vaadin which data to send from the browser. Any serializeable value present in the client-side event object can be sent. The available data depends on the specific event type.
Example: Defining the handleClick
method in a JavaScript Polymer template.
// same template as for the server-side event handler
static get template() {
return html`<button on-click="handleClick">Click me</button>`;
}
Example: Using the @EventData
annotation to get get additional data in the Java template class.
@Tag("event-handler")
@JsModule("./com/example/event-handler.js")
public class EventDataHandlerPolymerTemplate extends PolymerTemplate<TemplateModel> {
@EventHandler
private void handleClick(@EventData("event.altKey") boolean altPressed,
@EventData("event.srcElement.tagName") String tag,
@EventData("event.offsetX") int offsetX,
@EventData("event.offsetY") int offsetY) {
System.out.println("Event alt pressed: " + altPressed);
System.out.println("Event tag: " + tag.toLowerCase(Locale.ENGLISH));
System.out.println("Click position on element: [" + offsetX + ", "+ offsetY +"]");
}
}
-
The client parses the event data and sends the additional information back to the server for
event.type
,event.srcElement.tagName
andevent.offset[X/Y]
.
Note
|
If the EventData cannot be converted to the given format, the server could throw an exception, for example java.lang.ClassCastException: Cannot cast elemental.json.impl.JreJsonNumber to elemental.json.JsonObject . The client could also throw exceptions if the value given for EventData cannot be executed or converted to JSON.
|
Using the Template Repeater to Get Model-specific Event Data
You can use the <dom-repeat>
helper element to get model-specific items as objects in your event handler, provided you use beans to define your template model class. See Using Beans with a PolymerTemplate Model) for more.
Example: Creating the ModelItemHandlerPolymerTemplate
template and model class.
@Tag("model-item-handler")
@JsModule("./com/example/model-item-handler.js")
public class ModelItemHandlerPolymerTemplate
extends PolymerTemplate<MessagesModel> {
public static class Message {
private String text;
public Message() {
}
public Message(String text) {
this.text = text;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
public interface MessagesModel extends TemplateModel {
void setMessages(List<Message> messages);
}
@EventHandler
private void handleClick(@ModelItem Message message) {
System.out.println("Received a message: " + message.getText());
}
}
-
You can now handle click events on the server with the
Message
parameter type.
Example: Using the <dom-repeat>
(template repeater) in a JavaScript Polymer template.
class ModelItemHandler extends PolymerElement {
static get template() {
return html`
<dom-repeat items="[[messages]]">
<template><div class='msg' on-click="handleClick">[[item.text]]</div></template>
</dom-repeat>`;
}
static get is() { return 'model-item-handler' }
}
customElements.define(ModelItemHandler.is, ModelItemHandler);
-
When the item is clicked, the
handleClick
method is called on the server side and the data is identified byevent.model.item
.
Note
|
You can use the @ModelItem annotation with any value provided as a data path.
By default, the data path is event.model.item , but you should declare your data type in some manmer via the model definition, so that it can be referenced from the model.
|
Modifying Model Items Before Events
The @ModelItem
annotation is only a convenience way of accessing model data. The argument you receive in your event handler callback is the model data from the server side that you can access directly via your model instance. This means that the server does not update the model item on the client in any way. Therefore, if you create a custom event on the client side with data that you want to send to the server as a model item, it is ignored completely on the server side and the current model data is used instead. You should always keep your model in sync on the server and client, by updating it correctly.
To clearly demonstrate the point, the following example demonstrates the incorrect way to update the model.
Example: UserInfo
model and event handler definition.
public static class UserInfo {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public interface Model extends TemplateModel {
void setUserInfo(UserInfo userInfo);
}
@EventHandler
private void onClick(
@ModelItem("event.detail.userInfo") UserInfo userInfo) {
System.err.println("contact : name = " + userInfo.getName());
}
Example: JavaScript Polymer template that DOES NOT update the name of the UserInfo
bean instance.
class ContactHandler extends PolymerElement {
static get template() {
return html`
<input id="name" type="text">
<button on-click="onClick">Send the contact</button>`;
}
static get is() { return 'contact-handler' }
onClick(event) {
this.userInfo.name = this.$.name.value;
event.detail = {
userInfo: this.userInfo,
};
}
}
customElements.define(ContactHandler.is, ContactHandler);
-
This example results in the server-side model and the client being out of sync because client-side model is not updated correctly.
-
To correctly update sub properties in Polymer, replace
this.userInfo.name = this.$.name.value
withthis.set("userInfo.name", this.$.name.value)
. -
However, in this case the server-side model is updated automatically for you and there is no need to send this custom event at all. You can simply notify the server in some manner about the click event, for example via
this.$server
and a@ClientCallable
method. See Creating a Simple Component Using the PolymerTemplate API) for how to get the model value directly from the server-side model.
Additional Ways to Call the Server
There are two additional ways to call the server:
-
Use the
@ClientCallable
annotation: This annotation allows a Java method to be called from client-side code, using thethis.$server.serverMethodName(args)
notation. You can use this anywhere in your client-side Polymer class implementation. You can pass your own arguments to the method, as long as the types match the server-side method declaration. See @ClientCallable Annotation for more. -
You can also define
PropertyChangeListeners
when working with templates. See Enabling Property Changes for more.
Receiving Events After Server Update
In some cases, you may want to execute client-side logic after a component is updated from the server (during a round trip). For example, the component constructor is called on the client side, but it is too early to do anything with the component at this stage, because the component does not yet have data from the server side. In these circumstances, you can use the afterServerUpdate
method. When this method is defined for the component, it is called each time the component is updated from the server side, allowing you to configure the component with all available data.
Example: Using the afterServerUpdate
method in a JavaScript Polymer template.
import {PolymerElement,html} from '@polymer/polymer/polymer-element.js';
class MyComponent extends PolymerElement {
static get template() {
return html`
<div>
<div>[[text]]</div>
</div>`;
}
static get is() {
return 'my-component';
}
afterServerUpdate(){
console.log("The new 'text' value is: "+this.text);
}
}
customElements.define(MyComponent.is, MyComponent);
5C8D741C-2E59-4FC1-B1B9-F63697709259