2015/3/16 updated:

Now the proxy object in form binding will auto-detect the changes of proxy object and form status. In this sample, the following code segment can be omitted : BindUtils.postNotifyChange(…);
Introduction

We are glad to disclose the firsthand information on one of the most to die for features in ZK 8 – New Form Binding Approach. It can deeply support these types – Collections, Map, and POJO in a form concept, as a proxy object for developers to manipulate them when users edit data in the form field. Once the form is submitted, all the edited data will be synchronized back to the original data object.

The following class diagram shows the difference of Form Binding implementation between ZK 7 series and ZK 8.0.

Form Class Diagram

As shown in the diagram above, all user bean instances in the new Form Binding are proxy objects which can be used in the same way as the origin object without having to understand the underlying details of the Form Binding mechanism.

Books Management Demo

Here’s an example to demonstrate the form object (Book) with a collection property (Categories) in which users can edit the field data that belongs to Book or Categories in their own scope for caching.

Get Adobe Flash player

In this demo, only the following 3 classes – BooksViewModel, Book, and Category are used:

ZK8- New Form Binding Approach

With the new Form Binding, following the Java Proxy contract, the two classes – Book and Category needs to provide an empty constructor for the proxy mechanism to use. As shown in the diagram, in the Category class, we overwrite the hashcode and equals methods of the Category class to make sure only an unique category name exists.

Note: in the methods hashcode and equals, we cannot directly use the instance field to check, because the proxy object can be only handled by the method invocation, not the instance field. For example, use getName() instead of this.name.

In the BooksViewModel class, we provide 5 commands for the View to use.

  • editable: used for detail grid to be editable.
    @SmartNotifyChange("editable")
    @Command("editable")
    public void doEditable(@BindingParam("editable") boolean editable) {
    	this.editable = editable;
    }
    

    The @SmartNotifyChange is added since ZK 8.0, it means that notification is only triggered when the “editable” property has changed. Unlike @NotifyChange which triggers the notification every time.

  • cancel: used to cancel all changes. In fact, when this method is being invoked, it will trigger a NotifyChange for the “currentBook” so that the form object (a proxy Book object and its descendant) will reload the data from the original object to itself.
    @Command("cancel")
    @NotifyChange("currentBook")
    public void onCancel(@BindingParam("form") Form form) {
    	//2015/3/16 updated, this line can be omitted
    	//BindUtils.postNotifyChange(null, null, form.getFormStatus(), ".");
    }
    

    As you can see here, we manually post a NotifyChange for the form status which is used in the zul page to switch the status of the cancel button. The parameter of “form” can be either a Form interface or a Book class, we use it as a Form interface in this case.

  • save: used to save all changes from the form object to the original object and its descendants.
    @Command("save")
    @NotifyChange({"currentBook", "editable"})
    public void onSave() {
    	this.editable = false;
    }
    
  • addCategory: used to insert a new category to the form object.
    @Command("addCategory")
    public void doAddCategory(@BindingParam("form") Book form,
    	@BindingParam("cateName") String cateName) {
    	Set<Category> categories = (Set<Category>) form.getCategories();
    	categories.add(new Category(cateName));
    	//2015/3/16 updated, the following two lines can be omitted
    	//BindUtils.postNotifyChange(null, null, form, "categories");
    	//BindUtils.postNotifyChange(null, null, ((Form)form).getFormStatus(), ".");
    }
    

    The parameter of “form”, like we mentioned in the “cancel” command, is a proxy object of the “currentBook” instance of the BooksViewModel. The value returned from “form.getCategories()” is also a proxy object of the Set type for the “currentBook” instance.

    As a result we add a new category object that only affects the proxy object (Set type), not the original set in the “currentBook” instance.

  • removeCategory: used to remove a category from the form object.
    @Command("removeCategory")
    public void doRemoveCategory(@BindingParam("form") Book form,
    	@BindingParam("category") Category cate) {
    	Set<Category> categories = (Set<Category>) form.getCategories();
    	categories.remove(cate);
    	//2015/3/16 updated, the following two lines can be omitted
    	//BindUtils.postNotifyChange(null, null, form, "categories");
    	//BindUtils.postNotifyChange(null, null, ((Form)form).getFormStatus(), ".");
    }
    

    Here the concept of the removing category is the same as the “addCategory” command.

In the zul file, there is nothing different from the past, the only new feature we add in ZK 8 is that we provide a cleanup concept for the form field within the form proxy object.

For example,


... // omitted

	
	

As shown above in line 11, the “fx.resetEmptyStringValue” expression is used to clean up the value of the textbox when user clicks the buttons “addCategory” or “cancel”.

If ZK doesn’t provide these built-in methods, developer needs to declare the “getResetEmptyStringValue()” method by themselves in their own POJO object or else they will be initiated as a form proxy object.

ZK 8 provides 9 built-in methods in the form proxy object transparently for developers to clean up the component value as follows.

  • resetEmptyStringValue: returning an empty string value
  • resetNullValue: returning a null value
  • resetByteValue: returning a byte value (0)
  • resetShortValue: returning a short value (0)
  • resetIntValue: returning an int value (0)
  • resetLongValue: returning a long value (0L)
  • resetFloatValue: returning a float value (0.0f)
  • resetDoubleValue: returning a double value (0.0d)
  • resetBooleanValue: returning a boolean value (false)
  • resetCharValue: returning a char value (‘\u0000’)

You may have noticed in line 3 of the example above, we used “@load(1)” to switch the template, this is a trick to make it work within the current ZK version. However, we will introduced another new concept called Shadow Element to do the same thing but in a more clever, powerful, and flexible way in ZK 8.0, we will talk this topic another time, please stay tuned. 😀

Download
You can download the whole example from github.

If you enjoyed this post, please consider leaving a comment or subscribing to the RSS feed to have future articles delivered to your feed reader.

10 Responses to “ZK8: New Form Binding Approach”

  1. enferx says:

    Excellent feature for the new zk 8. It will be possible to use multiple collections with one simple proxy?. In your sample, let’s say we have a list of readers for one book, along with the categories. This kind of scenario could be handled in a single form validation?

  2. Ian Hayes says:

    Hello,

    This is interesting stuff.. I’ve been away from ZK for a while but I’m wondering if ZK8 will include new functionality to cover two distinct challenges I had with ZK6.5, namely:

    * In place editing within a grid, and updating other columns within a single row based on a data change in one cell of a row. Hence, if a grid includes four columns – ‘A’, ‘B’, ‘C’ and ‘D’ – if with in place editing if I change a data value in column ‘A’ for a specific row then the binding allows data updates to be applied to other cells in the same row. This is I think about having binding annotations at the row/bean level.

    * Providing MVVM template support on the ‘zk’ tag. This is about allowing a model class collection to be mapped to a zk tag. I had a requirement for this when trying to build grids with a dynamic set of columns,

    Keep up the good work!

  3. Mike says:

    You guys add new features faster than we can use them. I’m panting to try to follow. Kudos

  4. Jumper Chen says:

    @enferx, Yes, it should be possible to do so.

    @Ian Hayes, You can refer to the upcoming article post – http://books.zkoss.org/wiki/Small_Talks/2015/February/ZK8_Series:_UI_Template_Injection

    @Mike, Thanks.

  5. Nrak says:

    Sorry I’m confused, what is that “@load(1)” in the zul at “<rows children="@load(1) …" ?

    Shouldn't it be @load(fx.categories) ?

  6. Nrak says:

    Actualy how would I loop through the categories to add one row / category and at the same time be able to add an extra row at the end specific for the “add category” form ?

  7. Jumper Chen says:

    @Nrak,

    1. “@load(1)” is a tricky way to trigger children binding to create the template, you can use Apply shadow element in ZK 8 to do the same things.

    2. You could use IF/Choose shadow element with ForEach shadow element instead of children binding in ZK 8.

  8. Nrak says:

    Any reasons for using methods proxy instead of field proxy?
    This is a nightmare to work with when in debug mode …

  9. Nrak says:

    Also in your example the user cannot create twice the same item …
    What if I want to let the user do it?
    If I cannot define an equals on the object attribut ?

  10. Jumper Chen says:

    @Nrak,

    1. I am not quite sure how to use a field proxy in Java? is there any example or reference?
    2. You can use the method to get the original object for you to check the equivalence.
    https://www.zkoss.org/javadoc/latest/zk/org/zkoss/bind/proxy/FormProxyObject.html#getOriginObject()

Leave a Reply