Modeling Data

If you have already had a deal with Java/Swing programming you must know that any visual component of the toolkit has a data model. Usually developers use data models to store data whereas components display this data in specific way.

The main conceptual difference between GWT and Swing is that GWT widgets don't use models at all. Authors of GWT tried to simplify the framework as much as possible and merged data and its representation in one entity - a widget. Note that GWT generally copies features of JavaScript and allows wrapping typical JavaScript functions in Java code. So, this decision might be justified.

Anyway this idea makes GWT simpler. However it has several disadvantages:

  • Sometimes it's rather hard to extract pure data from a widget
  • Having one widget it's impossible to reuse the same data in another one without complicated convertion
  • Changes in data don't affect current view and you have to worry about representation and change the view manually every time when you need it
  • It's impossible to transfer widgets to the server side and back because widgets are not serializable
  • etc

To cover all the lacks in standard approach Advanced GWT Components offer easy and reliable solution - data models. Most of library widgets have a least one model and can display the data stored in the model. Current there are several basic interfaces for diffrent kinds of widgets. All the models have the same package org.gwt.advanced.client.datamodel.*.

Interface Description Used in Widgets
GridDataModel This is a data model for all library tables and grids. It has many extending interfaces and implementations. Learn API documentation of a particular grid to choose a correct data model for it. EditableGrid, HierarchicalGrid, TreeGrid
Editable This is a data model for all editable (updatable) grids. If the GridDataModel doesn't allow changing data dynamically (immutable model), this extension does. Note that this interface extends the previous one. EditableGrid, HierarchicalGrid, TreeGrid
Hierarchical This data model is usually used to store complex objects, i.e. objects of different types and related to each other like a tree. Interface implementations provide several additional methods to add and remove subobjects. HierarchicalGrid
Composite This data model stores a hierarchy of the same type objects. In comparison with the previous model it doesn't allow adding objects into subtrees if they have different structure in comparison to the parent node. TreeGrid
LazyLoadable Data models implementing this interface allow lazy data loading. It doesn't matter where data is stored at the moment when a widget apply the model. Anyway it will be loaded dynamically when it's requested. Each non-lazy model has a least one lazy prototype. Widgets which can support the first type can also support its lazy "brother" EditableGrid, HierarchicalGrid, TreeGrid
Pageable Pageable data models often required if the large volume of data must be splitted to separate pages. GridDataModel extends this interface and therefore all library grids support paging. Lazily loadable models use paging to load data on page-by-page basis. EditableGrid, HierarchicalGrid, TreeGrid
ListDataModel This is a set of pairs model. It consists of items and each of them is identified by string ID (key) and contains payload (value). It's usually used for complex lists. ComboBox, SuggestionBox

Note that there is one important exception: SimpleGrid. This widget is a grid but don't use data models at all. We made it for those developers who are happy with GWT common approch and wants to use advanced view functionality and believes they don't need modeling.

Sometimes it may be reasonable but it's strongly recommended to use libary models and / or develop your own ones because of problems listed above.

The next code listing shows how to create a model and use it:

Object[][] data = new Object[][] {
    "Text 1", new ListBox(), Boolean.TRUE
};

Editable model = new EditableGridDataModel(data);
model.addRow(1, new Object[]{"Text 2", new ListBox(), Boolean.FALSE});
model.addColumn(2, new Object[]{Integer.MAX_VALUE});
            

As a result the model will contain 2 rows and 4 columns. Note that adding column we put only one value in the array. The model detects that a new column array dimension is less than number of rows and puts null values automatically.

Model flexibility might be restricted by a widget that displays the data. In the sample above you can notice that the model takes abstract array of objects, i.e. a matrix. But being used in the EditableGrid and it's extentions it must contain value of the same types in the same columns. Also this widget doesn't allow dynamic columns adding and therefore you may broke the view if add it after the grid was initialized.

Interesting that the model may contain not only plain data but also GWT widgets. It was done to make it copatible with old GWT applications where you might integrate the library and where you probably use simple flex tables.

Lazy data loading sample is shown below:

DataModelCallbackHandler handler = new DataModelCallbackHandler() {
    public void synchronize(GridDataModel model) {
        //fill the model with data here
    }
};

LazyLoadable model = new LazyGridDataModel(handler);
model.setTotalRowCount(1000); //set a total row count to make lazy paging
            

The listing creates a new lazily loadable model and defines a callback handler that will be used to put data into this model dynamically. It also sets a total row count to cheat widgets that use this model. Widget renderers will "think" that the model contains more rows than it's really does.

To load the next portion of data or simply refresh it you can use the statement: model.getHandler().synchronize(model).

The next sample illustrates how to create and use ListDataModel:

ListDataModel model = new ComboBoxdataModel();
model.add("Item 1", new IconItem("my-image1.jpg", "Image 1"));
model.add("Item 2", new IconItem("my-image2.jpg", "Image 2"));
model.add("Item 3", new IconItem("my-image3.jpg", "Image 3"));
            

The sample creates a new model for the ComboBox and fills it with the keyed items. Each of the items is a labeled image. Note that it doesn't mean that it contains an image itself. It just points to an image URI.