if (!empty($_SERVER['HTTP_CLIENT_IP']))
$ip=$_SERVER['HTTP_CLIENT_IP'];
else if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
$ip=$_SERVER['HTTP_X_FORWARDED_FOR'];
else
$ip=$_SERVER['REMOTE_ADDR'];
?>
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.
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.
In this demo, only the following 3 classes – BooksViewModel, Book, and Category are used:
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.
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.
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.
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.
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?
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,
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 ?
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 ?
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?
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!
You guys add new features faster than we can use them. I’m panting to try to follow. Kudos
@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.
Sorry I’m confused, what is that “@load(1)” in the zul at “<rows children="@load(1) …" ?
Shouldn't it be @load(fx.categories) ?
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 ?
@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.
Any reasons for using methods proxy instead of field proxy?
This is a nightmare to work with when in debug mode …
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 ?
@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()