Integration of GWT widgets with Vaadin can be done in two basic ways:
by modifying the original widget or by extending it and adding the integration
code in the subclass. The latter way is actually the way the standard
client-side components in Vaadin are done: they simply inherit the
corresponding standard GWT widgets. For example,
VButton
inherits GWT Button
.
The client-side integration code has the following tasks:
The integration is broken down in the following sections into server-client
deserialization done in updateFromUIDL()
and
client-server serialization done with
updateVariable()
. The complete example of the
integration of the Color Picker widget is given at the end of this section.
If you are using the Eclipse IDE, the Vaadin Plugin for Eclipse allows easy creation of a stub for a new widget, alongside its server-side component. It also manages the widget set for you automatically. See Section 11.2.1, “Creating a Widget” for detailed instructions.
While the use of Vaadin does not require the use of any particular naming
conventions for GWT widgets, some notes regarding naming may be
necessary. Even though Java package names make it possible to use
identical class names in the same context, it may be useful to try to make
them more distinctive to avoid any inconvenience. GWT uses plain names for
its standard widgets, such as Button
. The standard
components of Vaadin use identical or similar names, but that does not
cause any inconvenience, because the GWT widgets and server-side
components of Vaadin are never used in the same context. For the
client-side components of Vaadin, we use the "V
"
prefix, for example VButton
. In the Color Picker
example, we use GwtColorPicker
for the GWT widget,
VColorPicker
for the integration implementation,
and ColorPicker
for the server-side component. You
may wish to follow similar conventions.
Notice that the naming convention changed when IT Mill Toolkit was renamed
as Vaadin. The prefix for client-side widgets in IT Mill Toolkit was
I
, which was changed to V
in
Vaadin. Similarly, CSS style name prefixes were changed from
i-
to v-
.
To receive data from the server, a widget must implement the
Paintable
interface and its
updateFromUIDL()
method. The idea is that the
method "paints" the user interface description by manipulating the HTML
tree on the browser. Typically, when using composite GWT components, most
of the DOM tree manipulation is done by standard GWT widgets.
An implementation of the updateFromUIDL()
method
must include some routine tasks:
updateComponent()
and return if it
succeeds
ApplicationConnection
object. The widget needs to know it to be able to initiate a server
request when a browser event occurs.
The latter two of these tasks are not needed if the widget does not handle any user input that needs to be sent to server.
The following excerpt provides a skeleton for the
updateFromUIDL()
method and shows how the
component identifier and connection object reference are managed by a
widget.
String uidlId; ApplicationConnection client; ... public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { if (client.updateComponent(this, uidl, true)) return; this.client = client; uidlId = uidl.getId(); ... }
The updateComponent()
call has several functions
important for different kinds of components. It updates various default
attributes, such as disabled
,
readonly
, invisible
, and
(CSS) style
attributes. If the
manageCaption
argument is true
,
the call will also update the caption of the component. By default, the
caption is managed by the parent layout of the component. Components,
such as a Button
, that manage the caption
themselves, do not need management of the caption.
The updateComponent()
is also part of the
transmutation mechanism that allows a single server-side component to have
alternative client-side implementations, based on its parameters. For
example, the Button
server-side component can
manifest either as a clickable VButton
or as a
switchable VCheckBox
widget on the client-side. If
the parameters are changed, the client-side widget can be replaced with
another dynamically. Determination of the correct implementation is done
in a WidgetSet
. If
updateComponent()
returns
true, the client-side engine can attempt to
replace the implementation. For more details on the transmutation
mechanism, see Section 11.5, “Defining a Widget Set”.
The component identifier is used when the component needs to serialize its updated state to server. The reference to the application connection manager is needed to make the server request. If a component does not have any state changes that need to be sent to the server, management of the variables is not needed. See Section 11.4.2, “Serialization of Component State to Server” below for further details.
The design of the client-side framework of Vaadin, because the
Paintable
is an interface and can not store any
references. Having an API layer between GWT and custom widgets would be a
much more complicated solution.
User input is handled in GWT widgets with events.
User input is passed to the server using the
updateVariable()
method. If the
immediate
parameter is
false
, the value is simply added to a queue to be
sent to the server at next AJAX request. If the argument is
true
, the AJAX request is made immediately, and
will include all queued updates to variables. The
immediate
argument is described in more detail
below.
if (uidl_id == null || client == null) return; client.updateVariable(uidl_id, "myvariable", newvalue, immediate);
The client
of the above example is a reference to
the ApplicationConnection
object that manages
server requests. The uidl_id
argument is the UIDL
identifier obtained during a updateFromUIDL()
call with uidl.getId()
method.
The updateVariable()
method has several varieties
to send variables of different types.
Table 11.1. UIDL Variable Types
Type | Description | UIDL Type |
---|---|---|
String | String object. | s |
int | Native integer value. | i |
long | Native long integer value. | l |
float | Native single-precision floating-point value. | f |
double | Native double-precision floating-point value. | d |
boolean | Native boolean value. | b |
Object[] |
Array of object data. The
toString() method is used to
serialize each of the objects. The content strings are
escaped with escapeString() , to
allow characters such as quotes.
| a |
This serialization mechanism is intended to be as simple as possible in most cases, when the user input is typically just one state variable, while also allowing the serialization of more complex data, if necessary.
Server-side components that inherit
AbstractComponent
have an
immediate
attribute, set with
setImmediate()
. This attribute dictates
whether a component makes a server request immediately when its state
changes, or only afterwards. For example, there is no need to send the
contents of a "Username" TextField
before the
"Login" button has been clicked. On the other hand, the server can set
the TextField
as immediate to receive changes
for example when the component loses focus.
Most widgets should support immediateness by receiving the
immediate
attribute from the UIDL message that
renders the widget. The following example is extracted from the
VTextField
implementation.
// Store the immediate attribute in a member variable private boolean immediate = false; ... public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { if(client.updateComponent(this, uidl, true)) return; // Receive and store the immediate attribute immediate = uidl.getBooleanAttribute("immediate"); ... } public void onChange(Widget sender) { if(client != null && id != null) { // Use the stored immediate attribute to say // whether or not make the server request // immediately. client.updateVariable(id, "text", getText(), immediate); } }
In some widgets, the immediate
attribute would
have little meaning, and in fact an accidental
false
value would cause undesired
behaviour. For example, a button is always expected to send a request
to the server when it is clicked. Such widgets can simply use
true
for the immediate
argument in updateVariable()
. For example,
VButton
does as follows:
public void onClick(Widget sender) { if (id == null || client == null) return; client.updateVariable(id, "state", true, /* always immediate */ true); }
Below is a complete example of an integration component for the Color Picker example. It demonstrates all the basic tasks needed for the integration of a GWT widget with its server-side counterpart component.
import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.Paintable; import com.vaadin.terminal.gwt.client.UIDL; public class VColorPicker extends GwtColorPicker implements Paintable { /** Set the CSS class name to allow styling. */ public static final String CLASSNAME = "example-colorpicker"; /** Component identifier in UIDL communications. */ String uidlId; /** Reference to the server connection object. */ ApplicationConnection client; /** * The constructor should first call super() to initialize * the component and then handle any initialization relevant * to Vaadin. */ public VColorPicker() { // The superclass has a lot of relevant initialization super(); // This method call of the Paintable interface sets // the component style name in DOM tree setStyleName(CLASSNAME); } /** * This method must be implemented to update the client-side * component from UIDL data received from server. * * This method is called when the page is loaded for the * first time, and every time UI changes in the component * are received from the server. */ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { // This call should be made first. Ensure correct // implementation, and let the containing layout // manage the caption, etc. if (client.updateComponent(this, uidl, true)) return; // Save reference to server connection object to be // able to send user interaction later this.client = client; // Save the UIDL identifier for the component uidlId = uidl.getId(); // Get value received from server and actualize it // in the GWT component setColor(uidl.getStringVariable("colorname")); } /** * Override the method to communicate the new value * to server. **/ public void setColor(String newcolor) { // Ignore if no change if (newcolor.equals(currentcolor.getText())) return; // Let the original implementation to do // whatever it needs to do super.setColor(newcolor); // Updating the state to the server can not be done // before the server connection is known, i.e., before // updateFromUIDL() has been called. if (uidlId == null || client == null) return; // Communicate the user interaction parameters to server. // This call will initiate an AJAX request to the server. client.updateVariable(uidlId, "colorname", newcolor, true); } }