Exploring data binding with Gwittir

January 30th, 2008 - Written by in Using GWT

is a library for GWT that provides a lot of interesting features including data binding, animation, reflection, and more. To help me learn more about this library, I decided to take it a spin and create a small GWT application to experiment with Gwittir’s data binding capabilities. So what does data binding give you? It allows you to glue together your user-interface widgets with the properties on your domain model. Whenever a user does something to a bound widget, its associated property in the model will be updated automatically. The binding is bi-directional as well, so if you make a change to the model, the widget will also update itself to reflect the change. Neat! So some of the benefits of data binding are that it promotes good MVC design, and it saves you from writing all those event listeners to copy data back and forth between UI and model.

The sample application I created is this simple data entry form, which allows the adding of books to a table.

I first created a Book object to be my model. It is a simple JavaBean with three fields, title, year, and inStock and extends the AbstractModelBean class. AbstractModelBean implements the Bindable interface which allows an object to be bound by the Gwittir framework and gives us the necessary PropertyChangeSupport.

(com.gwtsite.gwittir.Book)

public class Book extends AbstractModelBean {
  private String title;
  private int year;
  private boolean inStock;
 
  public Book() {}
  public String getTitle() {
    return title;
  }
  public void setTitle(String title) {
    this.title = title;
  }
  // ... other getter and setters omitted

For the user interface, I created a composite BookForm widget to hold the input fields and a table which displays the added books. The Gwittir distribution includes several BoundWidgets (Button, TextBox, etc), which are just standard GWT widgets with some extra methods to make binding easier. To get this behavior in my BookForm widget, I extended AbstractBoundWidget. By doing this, I had to implement the getValue() and setValue() methods. For a composite widget like I’ve created, the value property is simply my Book model.

(com.gwtsite.gwittir.BookForm)

public BookForm() {
  this.setValue(new Book());
  // ...
}
public Object getValue() {
  return this.getModel();
}
public void setValue(Object value) {
  this.setModel(value);
}

Now that I have created my model and view, I need a controller to hook everything together. In Gwittir, this is called an action. For this, I created an AddBookAction class which implements the BindingAction interface. This interface has four methods, bind(), unbind(), set() and execute(). Lets look at the set() method first. The set() method gets called when our widget is initially attached to the browser window. It is responsible for doing all the dirty work and wiring up the Book properties to the widgets in our form.

The Gwittir Binding object represents the data binding between two bindable objects. It can also hold a list of child bindings which allow us to manage multiple bindings with one instance.

(com.gwtsite.gwittir.AddBookAction)

private Binding binding = new Binding();
 
public void set(BoundWidget widget) {
   BookForm bookForm = (BookForm)widget;
   Book book = (Book) bookForm.getModel();
   ...
   binding.getChildren().add(new Binding(book, "title", bookForm.titleText, "value"));

The above code demonstrates how we bind the title property of the Book object with the value property of the title TextBox of our BookForm UI widget.

Gwittir also provides support for adding validation to our bindings. I’ll demonstrate this by doing some validation on the year property. Lets say that we only allow books published after 1950 to be added to our list. To accomplish this, I created a custom Validator by implementing the Validator interface.

(com.gwtsite.gwittir.AddBookAction)

private class NewBooksOnlyValidator implements Validator
{
  public Object validate(Object value) throws ValidationException {
    String year = value.toString();
    if (new Integer(year).intValue() < 1950)
      throw new ValidationException("Must be after 1950.");
    return new Integer(year);
  }
}

Ok, so this is not truly correct code, but it will work for demonstration purposes. Now we need a way to show any validation errors. Gwittir provides a ValidationFeedback interface along with several implementations. I decided to use two implementations – the PopupValidationFeedback class which will display an error message next to the TextBox if the user enters an invalid year, and the StyleValidationFeedback class which will add a css class called validation-error which we can use to highlight any errors in red.

I can add these two implementations into a CompositeValidationFeedback object and pass it to the binding like this:

(com.gwtsite.gwittir.AddBookAction)

ValidationFeedback feedback =
        new PopupValidationFeedback(PopupValidationFeedback.RIGHT)
        .addMessage(NewBooksOnlyValidator.class, 
        "We only accept books published after the year 2000.");
CompositeValidationFeedback cvf = new CompositeValidationFeedback()
        .add(feedback)
        .add(new StyleValidationFeedback("validation-error"));
binding.getChildren().add(new Binding(book, "year", null, null, 
                                bookForm.publishedText, "value", 
                                new NewBooksOnlyValidator(), cvf));

The second method of our Action class is the bind() method. This gets called automatically after our BookForm is attached to the browser window. All it does is call bind() on our binding object and establishes the binding.

The last step is to call our Action’s execute() method. I call this from BookForm’s ‘Add book’ button.

(com.gwtsite.gwittir.BookForm)

addBookBtn.addClickListener(new ClickListener() {
  public void onClick(Widget sender) {
    if (getAction() != null) {
      getAction().execute(BookForm.this);
    }
  }
});

The execute implementation itself is actually quite simple. First it checks if the binding is valid. This will not be the case for example, if the user enters an invalid year. If the binding is valid, then we get the fully populated Book object from the form, and add it to our Table. Easy!

(com.gwtsite.gwittir.AddBookAction)

public void execute(BoundWidget widget) {
  BookForm bookForm = (BookForm)widget;
  Book book = (Book) bookForm.getModel();
  if (binding.isValid()) {
    bookForm.booksTable.add(book);
  }
}

Hopefully this small example will peak your interest in taking a closer look at what the Gwittir framework has to offer. It was created by Robert Cooper and Charlie Collins who have a new book coming out, called . So expect some cool stuff from this framework in the future.

References

17 Comments Stumble it!

17 Comments »

Comment by robert 'kebernet' cooper
2008-01-30 01:53:59

Great doc! Thanks!

Comment by Chris Fong Subscribed to comments via email
2008-01-30 08:00:25

Hey, no problem. I’d like to take a look at some of Gwittir’s other features in future tutorials as well.

 
 
Comment by Mike Shaffer
2008-01-30 07:52:27

Excellent job on documenting what I think will be one of GWT’s “killer-apps”. Cooper has done a nice job on Gwittir and I can’t wait to see what’s in store when GWT 1.5 comes around…

 
Comment by Mike Shaffer
2008-01-30 08:20:05

For some reason the rest of my post got whacked….to continue:

But unfortunately, your demo isn’t working on my machine. Using Eclipse 3.2 WTP and GWT 1.4.10 with JDK 1.5.0_02, I’ve added the inherits of com.googlecode.gwtx.Java, com.totsp.gwittir.Gwittir and com.totsp.gwittir.LoggingDisabled to my module xml file. Added both gwtx and gwittir as external jars to my build path (using Eclipse here…) and I recieve a ton of errors like “[ERROR] Line 81: The method close() is undefined for the type OutputStream”….

I’m curious to hear how you got your demo working.

Comment by Chris Fong Subscribed to comments via email
2008-01-30 08:35:32

Oh, I came across this error message too. In your project properties under ‘Java build path’ > ‘Order and Export’, make sure that gwtx jar is above gwt-user.jar.

There’s a FAQ about this issue here.

Comment by Mike Shaffer
2008-01-30 12:44:43

Yep, I’d seen that before and tried it, but no luck…I’ve added a bunch of detail at the gwittir user group….bummer.

 
 
 
Comment by Subscribed to comments via email
2008-04-30 07:28:51

Thank you for your article about gwittir!!
in fact, i am using gwittir too, but i have a problem now.
As we all know, in the AbstractBoundWidget, we can set an action by using setAction function. However, we can set only one action and even we can not change action in the runtime. but for me, i have a view who should have more than one actions, for example, insert, delete, update.
Could you tell me how can i implement this situation??
Thank you very much!

Comment by Chris Fong Subscribed to comments via email
2008-04-30 10:11:56

So your view would contain several widgets right? Each one could be bound to its own action.

Comment by cjianfeng Subscribed to comments via email
2008-04-30 11:13:15

unluckily, just one widget, i want to not only add some data to the widget, but also modify and delete its value, so i should have 3 action for the widget…….

Comment by Chris Fong Subscribed to comments via email
2008-04-30 11:24:24

I’m not sure then. I would ask on the Gwittir group and perhaps they can be more helpful:

 
 
 
 
2008-06-12 19:42:50

[...] If you’re interested in learning more about Gwittir, you can also check out the article I wrote on Gwittir Databinding. [...]

 
Comment by Lalit Subscribed to comments via email
2008-06-25 21:20:58

Hi,
Can anyone suggest me how i can change 2 row 2nd column value in this example if required.

Thanks

 
Comment by Boumediene Subscribed to comments via email
2008-09-10 07:57:08

hi
i want to have an example for create dynamique class and how to get getter methods.
thank u

 
Comment by Amarish
2008-09-17 21:41:24

Hi Chris,

This a great article. I was wondering where the full source code for this can be downloaded.

Thanks,

Amarish

Comment by Chris Subscribed to comments via email
2008-09-17 21:52:30

Hi Amarish,

Check out the gwtsite google code page:

You can download the source from the repository.

Chris

 
 
Comment by Rohit Vadera
2008-09-23 23:28:49

I tried to mplement the example. Unfortunately bound table is not at all appearing. What could be the reason?

 
Pingback by ???????????? JSF ??? Seam | Alexander Shchekoldin "all in one" blog
2010-07-07 14:10:52

[...] Exploring data binding with Gwittir [...]