What is Ext GWT 2.0?

«»

SHARE & COMMENT :

ModelType class

ModelType defines the structure of the raw data to enable the DataReader that deals
with XML or JSON data to map the raw data from XML or JSON ModelData objects.

For example, if we had source data that was an XML document with this structure:


 <books>
 <book>
 <title>The best book in the world</title>
 </book>
 <book>
 <title>The worst book in the world</title>
 </book>
 </books>
 

the ModelType definition would look like this:

GWT Articles


 final ModelType modelType = new ModelType();
 modelType.setRoot("books");
 modelType.setRecordName("book");
 modelType.addField("title");
 

The root of the XML document is books, so we indicate this using the setRoot method . The
record is book, so we use setRecord name to indicate this. Finally, a field of book is title,
so we add this to the model using addField.

ModelType can also be used with JSON data. In fact, the ModelType definition we just used
to represent the XML could be used with the following JSON without modification:


 {
 "books": [
 {
 "book": {
 "title": "The best book in the world"
 },
 "book": {
 "title": "The worst book in the world"
 }
 }
 ]
 }
 

Loader interface

Loaders are used for loading ModelData into a store, given a DataProxy and a
DataReader. The base interface for all loaders is Loader, the abstract implementation of
which is BaseLoader:

There are two types of loaders: one for lists that implement the ListLoader interface and one
for trees that implement the TreeLoader interface . We will leave the tree loaders until later
chapters and at the moment just look at the list loaders.

The default implementation of the ListLoader interface is BaseListLoader. There is also
BasePagingLoader, which extends the functionality of BaseListLoader to add paging support
and implements the PagingLoader interface.

Loaders can also sort data when loading it. This can be defined either by using the
setSortField and setSortDir methods , or by specifying a LoadConfig object.

LoadConfig

LoadConfigs define how data is loaded. The LoadConfig interface has a number of
implementations, including one only used for tree data. For now we will just look at
the list implementations.

The first is BaseListLoadConfig, which allows you to specify how the data is sorted
when loading.

BaseListLoadConfig also has two subclasses that refine loading further:

  • BaseGroupingLoadConfig—t hat allows you to group data by a specified field
    using the setGroupBy method
  • BasePagingLoadConfig—t hat provides paging support

How they fit together

Here is a summary of how the various backend components fit together:

  • GXT uses classes that implement the ModelData interface to store information
  • Stores provide a cache of ModelData on the client and provide this to
    data-backed components
  • DataProxies retrieve the raw data from a remote source
  • ModelType describes the structure of the raw data
  • Certain DataReaders use the ModelType to define how to take raw data and
    produce ModelData
  • Loaders load the data into the store using a DataProxy and a DataReader
  • LoadConfigs optionally tell the loader how to sort, group, or page the ModelData

We will now return to our FeedList class and modify it to use an RpcProxy,
BeanModelReader, and a ListLoader to populate the ListStore of the ListField
using remote data.

Time for action – using remote data with a ListField

    1. In the onRender method of the FeedList class , remove the line that retrieves
      the feed store from the Registry, and instead retrieve the feed service from
      the Registry:

 @Override
 protected void onRender(Element parent, int index) {
 super.onRender(parent, index);
 final ListField<BeanModel> feedList = new
 ListField<BeanModel>();
 final FeedServiceAsync feedService = (FeedServiceAsync)
 Registry.get(RSSReaderConstants.FEED_SERVICE);
 feedList.setStore(feedStore);
 feedList.setDisplayField("title");
 add(feedList);
 }
 
    1. Create a new RpcProxy to retrieve a list of Feed objects using the loadFeedList
      method of the FeedService GWT RPC service:

 RpcProxy<List<Feed>> proxy = new RpcProxy<List<Feed>>() {
 @Override
 protected void load(Object loadConfig,
 AsyncCallback<List<Feed>> callback) {
 feedService.loadFeedList(callback);
 }
 };
 
    1. Create a new instance of BeanModelReader to use to convert the Feed objects
      into BeanModel objects:

 BeanModelReader reader = new BeanModelReader();
 
    1. Now create a ListLoader that takes the RpcProxy and the BeanModelReader
      and uses them to load a list of BeanModel representations of the Feed objects:

 ListLoader<ListLoadResult<BeanModel>> loader = new
 BaseListLoader<ListLoadResult<BeanModel>>(
 proxy, reader);
 
    1. Define the feed store again, but this time define the Store so that it takes the
      ListLoader as a parameter in order to use the loader to populate the store:

 ListStore<BeanModel> feedStore = new ListStore<BeanModel>(loader);
 
    1. Finally, add a call to the load method of the ListLoader to trigger the loading of
      the Store.

 loader.load();
 
    1. Start the application, and now the feeds that were previously saved will be loaded
      into the feed list:

What just happened?

We modified the FeedList ListField so that it now retrieves the required data from the
server using a call to a GWT RPC service.

Pop quiz – right tool for the job

Match the following requirements with the most suitable DataProxy, DataReader, and
Loader to achieve the goal:

    1. You have XML data on the same server as your application and you want to display it
      in one list.
    2. You have a set of JavaBeans on your server and you want to be able to display them
      in a paged list.
    3. You have a list of Model data and you want to display it in one list.
    4. You have JSON data on the same server as your application and you want to display
      it in a paged list.
    5. You have JSON data on a server with a diff erent domain from your application and
      you want to display it in one list.

Have a go hero – loading items

In a moment, we are going to load the items of a feed. To do this, we need to first implement
the following:

  1. A class named Item in the shared.model package. This class should extend
    BaseModel and needs to provide setters and getters for properties named:
    category, description, link, and title.
  2. A method in the FeedService named loadItems that takes an URL String of a
    feed and returns a List of Item objects.
  3. A corresponding asynchronous loadItems method in the
    FeedServiceAsync class.
  4. An implementation of the loadItems method in the FeedServiceImpl class that
    makes use of JDOM.

Attempt to implement this functionality using the work we have done with the Feed
object as a guide. Note that as the Item class will extend BaseModel, a corresponding
BeanModelMarker is not required.

Solution:

See the Item, FeedServiceAsync, and FeedServiceImpl class es in the example code.

Grid

GXT contains Grid components with many diff erent features. However, at the moment we
are just going to look at a basic grid and how to get data into it. When constructing a Grid
object, it requires both a ListStore and a ColumnModel to be specified.

ColumnConfig

A ColumnConfig object defines a column that a Grid will display. It specifies the data
that the columns will use and how it should be rendered. These are then collected into
a list and used in the constructor of a ColumnModel object, which acts as a container for
the ColumnConfigs and can in turn be used in the constructor of a Grid.

Grid Example

We are now going to return to our example application and add a Grid that will display RSS
items from an RSS feed.

Time for action – creating the ItemGrid

    1. Create a new class named ItemGrid in a new package named client.grids.
    2. The new class should extend the LayoutContainer c lass and override the
      onRender method:

 public class ItemGrid extends LayoutContainer {
 @Override
 protected void onRender(Element parent, int index) {
 super.onRender(parent, index);
 ..
 }
 }
 
    1. Create a constructor for the class that sets the layout of the underlying
      LayoutContainer to be a FitLayout:

 public ItemGrid() {
 setLayout(new FitLayout());
 }
 
    1. In the onRender method, define the ColumnConfigs for the Grid and add them
      to a list. One column should use the title field of the Feed object and the other
      the description field:

 final List<ColumnConfig> columns = new ArrayList<ColumnConfig>();
 columns.add(new ColumnConfig("title", "Title", 200));
 columns.add(new ColumnConfig("description", "Description", 200));
 
    1. Create a ColumnModel passing the list of ColumnConfig objects to the
      constructor:

 final ColumnModel columnModel = new ColumnModel(columns);
 
    1. We now need to define test data to load. Fortunately, there is an example RSS file
      available with the specification. Create a constant to store the String for the URL:

 final String TEST_DATA_FILE =
 "http://cyber.law.harvard.edu/rss/examples/rss2sample.xml";
 
    1. Retrieve the feed service from the Registry:

 final FeedServiceAsync feedService = Registry
 .get(RSSReaderConstants.FEED_SERVICE);
 
    1. Create an RpcProxy that uses the loadItems method of the FeedService to
      retrieve the Item objects for the feed at the URL defined in the TEST_DATA_FILE
      constant:

 RpcProxy<List>Item>> proxy = new RpcProxy<List>Item>>() {
 @Override
 protected void load(Object loadConfig,
 AsyncCallback<List<Item>> callback) {
 feedService.loadItems(TEST_DATA_FILE, callback);
 }
 };
 
    1. Create a BaseListLoader that uses the RpcProxy. Note that as Item extends
      BaseModel, a DataReader is not needed:

 ListLoader<ListLoadResult<Item>> loader = new
 BaseListLoader<ListLoadResult<Item>>(
 proxy);
 
    1. Now create a ListStore for the Item objects:

 ListStore<ModelData> itemStore = new ListStore<ModelData>(loader);
 
    1. We can now create a grid using the Store and the ColumnModel. Also, set the auto
      expand column to description so that the description column expands to fill the
      available space:

 Grid<ModelData> grid = new Grid<ModelData>(itemStore,
 columnModel);
 grid.setBorders(true);
 grid.setAutoExpandColumn("description");
 
    1. Call the load method of the ListLoader to load the Item objects into the
      Store of the Grid:

 loader.load();
 
    1. Add the Grid to the underlying LayoutContainer:

 add(grid);
 
    1. Finally, we can set the layout of RssMainPanel to FitLayout and add a new
      instance of ItemGrid in the constructor.

 public RssMainPanel()
 {
 setHeading("Main");
 setLayout(new FitLayout());
 add(new ItemGrid());
 }
 
    1. Now start the application and it will have a grid populated with the sample
      RSS file’s data:

What just happened?

We created a Grid, which makes use of a Store that is populated using Item objects
retrieved from the server. We saw how to use a DataProxy, DataReader, and Loader
to retrieve the Item objects, and load them into the ListStore.

GridCellRenderer

At the moment, in our sample application’s item grid, we are displaying a single field in
a column. However, if we want to combine fields or make them more than just plain text,
we can use the GridCellRenderer. This enables us to specify the generation of HTML
to render in a cell rather than the plain text value of a field.

Once defined, we can apply a GridCellRenderer to an entire column by using the
setRenderer method of ColumnConfig.

We are now going to use a GridCellRenderer in our application’s ItemGrid. Instead
of the title and description appearing in diff erent columns, we are going to use the
GridCellRenderer to display the title above the description in the same column.

GridCellRenderer objects must include a render method, which returns an HTML string.

Time for action – using a GridCellRenderer

    1. In the onRender method of the ItemGrid class, create a new GridCellRenderer
      named itemsRenderer with a render method:

 GridCellRenderer<ModelData> itemsRenderer = new
 GridCellRenderer<ModelData>() {
 public String render(ModelData model, String property,
 ColumnData config, int rowIndex, int colIndex,
 ListStore<ModelData> store, Grid<ModelData> grid)
 {
 }
 };
 
    1. Implement the render method so that it retrieves the title and description fields
      from the model and combines them in an HTML string, which is returned from
      the method:

 GridCellRenderer<ModelData> itemsRenderer = new
 GridCellRenderer<ModelData>() {
 public String render(ModelData model, String property,
 ColumnData config, int rowIndex, int colIndex,
 ListStore<ModelData> store, Grid<ModelData> grid)
 {
 String title = model.get("title");
 String description = model.get("description");
 return "<b>" + title + "</b><br/>" + description;
 }
 };
 
    1. Create a new ColumnConfig with the ID of items, the header of Items, and set
      the renderer to be the itemsRenderer we created in the previous step:

 ColumnConfig column = new ColumnConfig();
 column.setId("items");
 column.setRenderer(itemsRenderer);
 column.setHeader("Items");
 
    1. Add the items column to the list of columns in place of the previous title and
      description columns:

 columns.add(column);
 final ColumnModel columnModel = new ColumnModel(columns);
 
    1. Change the grid to auto expand the items column instead of the now non-existent
      description column:

 grid.setAutoExpandColumn("items");
 
    1. Start the application and notice how the GridCellRenderer has rendered the
      fields in a single column:

What just happened?

We used a GridCellRenderer to create an HTML string to display two fields in the same
column with formating instead of just plain text.

Summary

In this chapter, we have introduced GXT’s data-backed components. We have made use
of a Store to cache data locally. We linked a ListField to a Store to show how the
components’ values could automatically be updated when data in a Store changed.

We then added to the server-side of our example application by providing a service that
can persist and retrieve remote data.

We went on to use the service to retrieve remote ModelData and used that data to
populate a Grid. We then formatted the Grid using a GridCellRenderer.

In the next chapter, we will look at some more advanced grids and also look at the useful
tree-based components.

GWT Articles

«»

Comments

comments

Pages: 1 2 3

About Krishna Srinivasan

He is Founder and Chief Editor of JavaBeat. He has more than 8+ years of experience on developing Web applications. He writes about Spring, DOJO, JSF, Hibernate and many other emerging technologies in this blog.

Speak Your Mind

*

Close
Please support the site
By clicking any of these buttons you help our site to get better