Blog

Vaadin 7 Loves JavaScript Components

By  
Henrik Paul
·
On Aug 28, 2012 6:28:00 AM
·

NOTE: This blog post is outdated and the resources are no longer available. You can find an updated tutorial here.

Using JavaScript components in Vaadin 7 is a breeze. Sure, Vaadin has had Window.executeJavaScript() for a good while now, but it's quite limited in what you can actually do with it. For one, if you have a dependency to a JavaScript file, it can be tricky to ensure that it's loaded prior to your JavaScript call.

Like a traditional Vaadin 7 GWT component, a JavaScript component consists of four parts: the server-side component, state, connector and the client-side widget. In the simpler examples (like the one we're going to go through next), it's usually better to combine the connector and the client-side widget. However, when linking a ready-made javascript widget with this JavaScript component functionality, you're only going to write the connector, that controls the widget (being the library).

Pretty much anything you can do with a GWT widget, you can do with a JavaScript widget (as long as it's not a ComponentContainer). But for this example, we're going to take a look at an example that is as simple as possible, just to show how the various parts work. You can certainly do more complex (and useful) things as JavaScript widgets, but this isn't about what you can do, but how it all works.

We're going to make a label on a budget: It simply displays a piece of XHTML, and that's it.

The Easy Part: Server-Side

 

@JavaScript({ "js_label.js" })
public class JsLabel extends AbstractJavaScriptComponent {

  public JsLabel(String xhtml) {
    getState().xhtml = xhtml;
  }

  @Override
  protected JsLabelState getState() {
    return (JsLabelState) super.getState();
  }
}

 

As we can see, our component is very bare-bones. It has only a constructor that takes the label's contents as a parameter. This parameter is then passed on to the label's own shared state, to be sent over the wire to the client side.

The interesting and important parts of this code are the annotation and the class JsLabel extends. We'll get back to the getState().xhtml statement in a while.

@JavaScript informs Vaadin of any JavaScript files that are required by your widget. In our case the only requirement is js_label.js, which is the client-side implementation of JsLabel (we'll take a look at the file later). Since we've given a relative path to the file, it needs to be deployed in the same Java package as the JsLabel class. So, in my IDE, I have both js_label.js and JsLabel.java files side by side. If you need, you can list more files in the string array, and you can also give them in an absolute URL format instead.

AbstractJavaScriptComponent is the class we want to extend. It enables the two-way communication between JavaScript and Vaadin, with the help of the shared state object.

Note that Vaadin knows which state class to use because we override getState() and specify it with your own shared state class. But this is nothing JavaScriptComponent specific, and is a requirement with all Vaadin 7 components.

Getting There: State

 

public class JsLabelState extends JavaScriptComponentState {
    public String xhtml;
}

 

Halfway between the server and the client is the state. A Vaadin state object is just an object whose sole purpose is to carry data back and forth between the server and the client. Since we're developing a JavaScript widget, we need to extend JavaScriptComponentState.

To keep the code short and also symmetric with the JavaScript side (as you will soon see), I've opted to define the xhtml field as public. There's nothing stopping me from adding a getter and setter there, but since a state class is nothing more than a data transfer object, and no logic should ever be included in a state, a getter and a setter for fields are just unnecessary boilerplate in our case. Should you add the getters and setters, the field must be made private.

Note: Technically, it is possible to have our state class as an inner class within JsLabel to make the code even more compact. The problem with this approach is that inline state classes only work with JavaScript components. GWT shared state classes do not work as inner classes, except in some very special cases. Also, if we avoid calling getState(), we need to remember to manually call markAsDirty() whenever we change the state. To keep confusion to a minimum, it is highly recommended to keep all your state classes separate from the component.

The Lean Meat: Client-Side

 

org_vaadin_blog_JsLabel = function() {
  var e = this.getElement();
	
  this.onStateChange = function() {
    e.innerHTML = this.getState().xhtml; 
  }
}

 

This is the js_label.js file we had in the @JavaScript annotation earlier. The client-side is, in all its simplicity, pure JavaScript. There's two things of interest here: the function's name and a decorated this reference.

There's a naming convention we need to follow. This helps Vaadin find the correct JavaScript function to call when our component is attached. We take the fully qualified class name of the server-side component, and just replace the dots with underscores. So, in our case, our JavaScript function needs to be org_vaadin_blog_JsLabel. Don't worry, though. If you get it wrong, Vaadin is nice enough to tell you what (it thinks) it should be named as.

The this inside that function has some added functionality courtesy of Vaadin 7. The complete specifics can be read up on the JavaDoc of AbstractJavaScriptComponent (you can read it in alpha 3's JavaDoc), but we'll only use the two arguably most important features. this.getElement() gives the DOM element that was created for this widget by Vaadin, and this.getState() is the way to access the state. In our case, we just read the XHTML string from the state, and set the DOM element's innerHTML as whatever we got over the wire. Unfortunately, a component's state can't be modified on the client side, to be updated on the server side.

As mentioned in the intro, this example file is both a connector and a widget at the same time. The connector's responsibility is to handle the communication between the state and the widget. In our case, it would only make the code more confusing to separate these two aspects, thus the widget and the connector are kept in the same javascript file.

Note that any possible getters and setters in a state can not be used on the JavaScript side. The values are accessed directly as properties. This is true even if you explicitly have written the accessors in your state class.

Done!

We're all set to deploy our code and give it a spin. Indeed, no widgetset compilation required. Ever. This one of the greater benefits you get from working with JavaScript widgets - no need to involve GWT at all. If you notice a bug in your client side code, you can simply edit your JavaScript file, redeploy and the changes are shown immediately.

You can download the whole Eclipse project (51MB) of what we've done here, and give it a try yourself.

There's however no need to throw all GWT widgets in the trash can just yet. There are a few downsides to this method aswell: You obviously lose the static typing of Java, when writing directly with JavaScript. Also, it's quite tricky to refer to any GWT code, so you really shouldn't even try. And last, but not least, you lose all help from the GWT complier regarding browser incompatibilities, and all that becomes your own mess to handle.

Summa summarum: Vaadin's JavaScript Component mechanism is excellent for linking existing JavaScript widgets into Vaadin. It's also handy when you already are well versed in JavaScript, and want to do small and quick things on the client side. But GWT is still the best alternative when doing even slightly more complex and reliable components for Vaadin.

Now you have to choose wisely: Build with GWT, or build with JavaScript. It's really up to you.

If you want to read about linking an existing JavaScript component into Vaadin, you can read the Integrating a JavaScript component article in our wiki.

Henrik Paul
Henrik Paul works as a Scrum Master at Vaadin's product development. He has been working at Vaadin since 2008 with basically anything and everything, except in sales or administration. He's one of those annoying guys who is never satisfied with the status quo, and questions established practices constantly.
Other posts by Henrik Paul