Sencha Inc. | HTML5 Apps

Sencha GXT 2.x to 3.0 Migration Guide

Published Apr 30, 2012 | Jennifer Liu | Guide | Easy
Last Updated Apr 30, 2012

This Guide is most relevant to Sencha GXT, 2.x, 3.x.

Introduction

Sencha GXT 3.0 is the next generation of the components and tools that, in conjunction with the GWT compiler and runtime, make it possible to build large scale maintainable browser-based web applications. As part of this new release, we've made a number of changes from GXT 2.x, with several main goals in mind:

  1. Better compatibility with current and future GWT features
  2. More use of GWT best practices
  3. Simple to use out of the box, and able to be extended for specific use cases
  4. Able to run side-by-side GXT 2 releases.

As in GXT 2, a single module can be inherited into your project to begin using the library: com.sencha.gxt.ui.GXT. Several other modules have been created as well to make it possible to customize exactly how widgets will be drawn in specific situations. By not inheriting the main GXT module, you are able to limit what code will be included in your compile, and will have more control over what browser permutations to construct - it is possible to build a permutation for IE6, 7, 8, 9 as well as different versions of Firefox, and Chrome versus Safari - 13 in total. By default, when inheriting the main GXT module, these are collapsed down to the default GWT permutations - IE6-7, IE8, IE9, Firefox, and Safari/Chrome.

Many of the classes and features that were available in GXT 2 are present in 3 as well, though their names may have changed. Some are no longer possible or reasonable to keep in GXT itself or have been superseded by GWT features that we are now taking advantage of. Several of the main features that are no longer present are available now in a legacy jar, but are not expected to continue to receive improvements, and are offered only as a stopgap measure while switching to more modern GWT techniques.

To facilitate migrating large projects, GXT 2 and 3 can be on the same classpath at the same time - the basic package has changed from com.extjs.gxt to com.sencha.gxt. This, in conjunction with containers designed to adapt from 2.x to 3.x containers and layouts, will allow projects to migrate gradually if necessary.

Setup

The resources required to use GXT are all managed internally now - it is no longer necessary to keep a resources directory up to date. Instead, the GWT ClientBundle feature is used to manage images and stylesheets, making sure they are present as part of the compiled project. It is still necessary to link to a stylesheet from the main html page however - every compiled project will have a reset.css file, used to normalize differences between browsers. This should be linked to from your html page. There is no need to link to a gxt-all.css file, or any other css to load a specific theme, and other theming should be done within the project, not using external files.

As GXT 3 requires GWT 2.4 or later, and GWT 2.4 requires that the html page have a strict doctype, GXT 3 requires a strict doctype as well. This allows us to make sure that browsers will render content more consistently.

Either

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

or

<!!DOCTYPE html>

may be used in the host html page as a strict doctype.

Components

The basic concept of Components is entirely unchanged - they extend GWT Widgets, and provide additional behavior and lifecycle details. Components no longer draw their content lazily - this allows GXT widgets to work more effectively in UiBinder, and are generally easier to us. To mitigate concerns about performance hits that may result from this, consider the GWT class LazyPanel - this allows a set of widgets to be kept from being displayed until they are needed. GWT is also starting to use the PotentialElement class - we will watch the development of this feature, and make use of it as it is finalized.

An additional result of this change is that there are now very few component setters that can only be used before it is rendered, and none that can only be used post-render.

The Component lifecycle no longer includes the ComponentPlugin initialization process: Most plugins cannot be added to multiple components anyway, and the difference between adding a plugin to a component and initializing a plugin with a component is negligible.

GXT 3 events are now based off of the GwtEvent class, providing better consistency with existing GWT libraries and projects, and better type safety when adding handlers (formerly listeners) to objects. There is no longer an Observable interface, nor is there a BaseObservable class - EventBus instances can be used instead, and Has*Handler interfaces to declare where events can be fired from.

/** Declare a strongly typed handler for this specific event */
public interface CustomEventHandler extends EventHandler {
  /** The method may be named and typed for this event */
  public void onMyEvent(CustomEvent event);
}

/** Declare a new event object with whatever state it will convey */
public class CustomEvent extends GwtEvent<CustomEventHandler> {
  private GwtEvent.Type<CustomEventHandler> TYPE = new 
        GwtEvent.Type<CustomEventHandler>();
  public static GwtEvent.Type<CustomEventHandler> getType() {
    return TYPE;
  }
  
  @Override
  public GwtEvent.Type<CustomEventHandler> getAssocatedType() {
    return getType();
  }
  
  @Override
  protected void dispatch(CustomEventHandler handler) {
    /* Call the specific handler method to inform listeners that the event is happening */
    handler.onMyEvent(this);
  }
}

// Add a handler to an EventBus or HandlerManager for the specific event type
eventBus.addHandler(CustomEvent.getType(), new CustomEventHandler() {
  @Override
  public void onMyEvent(CustomEvent event) {
    // React to the event
  }
});

// The event can then be fired, and the handler will recieve it
eventBus.fireEvent(new CustomEvent());

XTemplates are now generated at compile-time, and create a SafeHtml instance instead of returning a String or being applied to an Element. This makes them usable anywhere SafeHtml can be used, especially in Cells in a Grid or other data widget. They are also able to act on any object with accessor methods for properties instead of first needing to translate objects into JavaScriptObject instances. The old runtime Template and XTemplate classes are available in the legacy jar if runtime templates are required. Check out our XTemplates Redesign blog post for more details.

XTemplates are more heavily used in Component internals for rendering, typically by the component’s appearance. This modification typically results in more efficient rendering, as well as easier to read and modify structure of any component by modifying the appearance and its template directly, rather than using a subclass to remove or rearrange dom elements, a more costly operation.

Many components are backed by a Cell implementation, allowing them to be rendered in any data widget that accepts a cell, including Grid, Tree, TreeGrid, and ListView. These cells in turn delegate to an appearance implementation, either by being given an instance in their constructor, or by relying on rebind rules typically defined in theme modules. These appearances then are responsible for drawing content using XTemplates and ClientBundles, and associating events that have occurred on elements with the behavior that this should initiate in the Cell or Component.

Ext GWT 2 relied on the El class as a way or wrapping dom elements to perform operations on them efficiently, using the flyweight pattern to avoid frequent object construction while still adding functionality. In GXT 3 the XElement class has been introduced, extending from the JavaScriptObject class Element

Layouts

In GXT 2.x, all Container subclasses could be assigned a Layout instance, either internally or externally. Most then also supported the ability to add widgets or components with layout data associated to them. Little could be done to require that a particular widget have the right kind of data or any data at all.

To help make this easier to write and understand, and to facilitate UiBinder declared layouts, there is no longer a Layout class, but containers declare how they will draw their children, and provide strongly typed add methods where possible. Some layouts are no longer required, such as the FitLayout -- any case where this might be used now typically already knows how to size a single child to itself, such as ContentPanel, Window, or Dialog; or the FormLayout -- with the creation of the FieldLabel, able to accept any widget as its contents, the FormLayout doesn’t provide any meaningful value. Other layouts have had their name changed - RowLayout has become HorizontalLayoutContainer or VerticalLayoutContainer, depending on the direction to use, whereas ColumnLayout has become CssFloatLayoutContainer.

Sencha GXT 2.x

Sencha GXT 3.0

Description

FlowLayout

FlowLayoutContainer

Allow HTML/CSS rules to define how children are drawn

FitLayout

N/A

Fit one item to the size of its parent - not required in GXT 3 for parents that don’t apply a layout

RowLayout

VerticalLayoutContainer

Size and position children based on layout data in a vertical stack based on parent’s assigned size

HorizontalLayoutContainer

Size and position children based on layout data in a horizontal row based on parent’s assigned size

ColumnLayout

CssFloatLayoutContainer

Sets the width of each child based on layout data, but allow positioning and height to be determined by HTML/CSS float rules

BorderLayout

BorderLayoutContainer

Positions and sizes children in five distinct regions of the parent. Children positioned around the edges are dealt with first, and the center gets the remaining space. Additional decoration and user-initiated sizing can be enabled for this layout

CenterLayout

CenterLayoutContainer

Positions all children within the parent so that they are centered based on both parent and child sizes

CardLayout

CardLayoutContainer

Sizes and positions all children to be the same size as the parent, but only allows one to be visible at a time

HBoxLayout

HBoxLayoutContainer

Positions children as a single horizontal row with support for automatic overflow (when there are too many widgets to display in the available width)

VBoxLayout

VBoxLayoutContainer

Positions children as a single horizontal column

FormLayout

N/A

Use FieldLabel instances to produce this same effect

AccordionLayout

AccordionLayoutContainer

ContentPanel children are displayed one at a time, with headers stacked to allow the user to select a panel to display. Defaults to sizing the visible child to available space.

HtmlLayoutContainer

Positions children based on css queries within a given body of html. No sizing is performed on the children.

NorthSouthLayoutContainer

Specialized container for up to three children, positioning them so that the top and bottom consume the space they need, while the center takes the rest of the size assigned to the parent.

Layouts in 2.x and 3.0

Data

In GXT 2.x, several model object interfaces and base classes were provided, such as ModelData, TreeModel, BaseModelData. These types allowed for a sort of psuedo-reflection by making each model responsible for tracking the mapping from a String key to the property it referred to. This could make it difficult to use existing POJO beans and to write code in a type-safe way. When AutoBeans and RequestFactory were released, it was difficult to effectively use them.

GXT 3 supports any bean-like object, with public accessors (getters and setters) through its XTemplates and through PropertyAccess, a mechanism to generate ValueProvider instances. ValueProvider is a way to deal with the problems of changing and reading values from outside the models in a generic way:

ValueProvider<Person, String> firstName, lastName;
Person p;

String f = firstName.getValue(p);
String l = lastName.getValue(p);

By keeping access to these properties external, the models aren’t required to extend from any base class or use any interface. All data widgets and stores use ValueProvider to read and write values, and XTemplates make use of them as well.

There are times when values need to be read from the models and used as keys in a store, or as labels in the ui -- read-only interfaces have been declared for these purposes, LabelProvider and ModelKeyProvider. PropertyAccess is able to generate these as well. Multiple providers can be created for a given path [d]but with different names using the @Path annotation. The @Path annotation can also be used to refer to nested properties as well -- where in GXT 2 one could say model.get(“owner.firstName”), the annotation would be written @Path(“owner.firstName”).

As part of these changes to support arbitrary model objects, we’ve also gone through and tightened up our use of generics to be as specific and consistent as possible throughout the library. In some places this has led to somewhat complex generics, but with the benefit of assuring that if the generic instances all are set up correctly, no class cast exceptions should be possible, and there should never be confusion[e] about how models are created and passed around.

Generic argument name

Typical meaning

M

Model object

C

Config object, typically passed to the server when loading data

V

Value, usually a property of M

D

Data, often passed over the wire, not directly used by model-consuming classes[f]

T, X

Everything else, rely on javadocs to be sure

Guide to generics arguments in GXT 3

Binding

With the introduction of the strongly typed GWT Editor framework, the need for a GXT specific framework has someone been reduced. The Bindings and FieldBindings classes are still available in the legacy jar, but Field and other form classes now implement the various Editor interfaces instead of expecting a FormBinding object to wrap it and give it a string to bind to. Fields still support handling and reporting local errors, but now as part of the GWT Editor framework they can display errors reported outside of the field itself, and can also pass errors up to the editor driver.

The Converter type, used in GXT 2 to convert values within the FieldBinding before setting them on the field and after reading them out of the field into the model, is still present and has been made into an interface with generics to ensure that it matches the expected type. It can be used with the Editor framework through the used of a ConverterEditorAdapter. This requires several generic arguments to ensure that the driver gets all of the details right - the actual type of the property, the type the field is intended to edit, and the actual field type to be used.

Stores

The Store, ListStore, and TreeStore classes have been cleaned up and updated. They now support any object at all, provided there is a way to obtain a key for each model. ModelKeyProvider instances are mandatory, a departure from 2.x, but this change allows the stores to have one less possible code path at runtime. This, along with careful rewriting and review of these classes, should make them significantly better performing, especially in cases where the contents are being changed while already filtered and or sorted.

A few methods have been renamed in ListStore to be more consistent with java.util.List - clear(), addAll(Collection), get(int), and several more have been changed to make the stores more flexible when manipulating the current filter and sort options.

Records have been changed slightly in light of support for any POJO bean and any implementation of ValueProvider. They can be completely ignored by invoking store.setAutoCommit(true) so that changes are made right away to the bean, or if autoCommit is false, then changes will be queued up in the Record object until they are committed or rejected. This is a break from 2.x where changes were made right away to the underlying model, but the original value was persisted. There are several reasons why this is not the case:

  1. Calling a setter on an object might have side effects, as any implementation can be used instead of always backing models by a Map<String,Object>. Additionally, as ValueProvider is just an interface, the setValue method might have other changes it makes beyond to the model.
  2. Object are permitted to have setters without getters, so there would be no way to know the original value to restore in certain cases - this wouldn’t come into the picture frequently, but it would cause exceptions when attempting to revert.
  3. A ListStore can be bound to a List property in an Editor using the ListStoreEditor class, and the Editor contract calls for changes not to be made until flush is invoked. This allows ListStore to be used more cleanly in an Editor.

TreeStore has been modified similarly to Store and ListStore to accept any object at all, and to expose the tree structure through methods instead of as a property of the models themselves. In addition to better performance characteristics and usable generics, this means that objects are not expected to describe their own structure, though they are permitted to by implementing TreeNode<T> recursively. These nodes then should be added to the TreeStore through the addSubTree and replaceSubTree methods. This structure will not be modified automatically - to obtain the full current structure use the getSubTree method and iterate over the results.

Data Widgets

Data Widgets in GXT 3 operate mostly the same as in 2.x - they are provided a Store from which to obtain data (and in some cases to persist changes), and have flexible options for displaying that data. The chief changes are around the use of ValueProviders to read content, Cells to display it, and the appearance pattern to modify how the data widgets generally collect their data.

Each data widget can be give a Cell instance to delegate rendering to, and in some cases such as the Grid and TreeGrid, multiple Cells can be used. Typically each one maps to a single property of the model currently being rendered, or the model itself, via a ValueProvider. In cases where the model itself is being edited, an IdentityValueProvider may be used, which always returns the model itself, to be passed along to the Cell for rendering.

In Ext GWT 2, Grid cells were rendered by GridCellRenderer instances, either returning a String or a Widget instance. If a Widget was used, one instance would be created for each row, which can become very expensive for many rows. Cells deal with this by using a single instance to draw all rows, and handling all logic with enough context to know exactly where and how each particular user interaction occurred. This results in efficient, responsive displays, even with large amounts of data - check out our fully loaded Cell Grid sample for an example of this.

Most CellGridRenderers that return HTML are easy to translate into Cells, especially with the help of XTemplates. Renderers in 2.x that would return stock Ext GWT components now can be replaced by matching Cells, as most GXT 3 components have a Cell that is actually used to do their rendering and handle their events. And writing new, custom Cells is fairly straightforward, and will result in better performing applications than drawing widgets for each row.

Share this post:
Leave a reply

Written by Jennifer Liu

Commenting is not available in this channel entry.