ZK dos and donts part1"

From Documentation
 
(36 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 
{{Template:Smalltalk_Author|
 
{{Template:Smalltalk_Author|
 
|author=Matthieu Duchemin, Engineer, Potix Corporation
 
|author=Matthieu Duchemin, Engineer, Potix Corporation
|date=January 2016
+
|date=March 2016
|version=ZK 8.0
+
|version=ZK 8
 
}}
 
}}
  
ZK Framework offer lots of features to simplify the creation of a Java based web application. As some of these features are not always known, we sometime come across suboptimal implementation. Usually, it only take a few simple steps to make them simpler and easier. Those aren't necessarily broken or damaging, but they can have positive effects without much changes or efforts.
+
=ZK Do's and Don'ts Part 1=
You will find here a few common mistakes in ZK, and solutions to avoid them.
+
ZK Framework offers a lot of features to simplify the creation of Java-based web applications. Some of these features are not always well known. From time to time, we come across suboptimal implementation. Usually, it only takes a few simple steps to turn them simpler and easier. Those aren't necessarily broken or damaging, but improving them can have very positive effects with few changes or efforts.
 +
You will find here a few cases where ZK efficiency can be maximized.
  
=ZK Do's and Dont's Part 1=
+
Example project available [https://github.com/zkoss-demo/zk-dos-and-donts here]
  
==Calling components directly when using a model==
+
=='''Calling components directly when using a model'''==
 
ZK offers default ListModel<ref>http://books.zkoss.org/wiki/ZK_Developer's_Reference/MVC/Model/List_Model</ref> implementations such as ListModelList. They provide an easy way to separate the view from the model. By providing a template or a renderer to control the appearance, and a model to handle the data.
 
ZK offers default ListModel<ref>http://books.zkoss.org/wiki/ZK_Developer's_Reference/MVC/Model/List_Model</ref> implementations such as ListModelList. They provide an easy way to separate the view from the model. By providing a template or a renderer to control the appearance, and a model to handle the data.
While delegating control to the model, it feel sometime "easier" to act directly on a component. One would use grid.getRows().appendChild(..) to add a new row, or use listbox.setSelectedIndex() to set the selection state of a Listbox.
+
While delegating control to the model, it sometimes feels "easier" to act directly on a component. One would use grid.getRows().appendChild(..) to add a new row, or use listbox.setSelectedIndex() to set the selection state of a Listbox.
 
If the components content is directly controlled by the application, this may be correct. However, if the content is controlled by a model, the model itself should perform these actions.
 
If the components content is directly controlled by the application, this may be correct. However, if the content is controlled by a model, the model itself should perform these actions.
;Do:
+
<br/>
:*Use ListModels instead of basic collections when assigning a model to a component.
+
[[Image:Dndsmalltalk-check-icon.png]] '''Do:'''
:**List – ListModelList <ref>https://www.zkoss.org/javadoc/latest/zk/org/zkoss/zul/ListModelList.html</ref>
+
*Use ListModels instead of basic collections when assigning a model to a component.
:**Set – ListModelSet <ref>https://www.zkoss.org/javadoc/latest/zk/org/zkoss/zul/ListModelSet.html</ref>
+
**List – <javadoc>org.zkoss.zul.ListModelList</javadoc>
:**Map - ListModelMap <ref>https://www.zkoss.org/javadoc/latest/zk/org/zkoss/zul/ListModelMap.html</ref>
+
**Set – <javadoc>org.zkoss.zul.ListModelSet</javadoc>
:**Object[] or Enum – ListModelArray <ref>https://www.zkoss.org/javadoc/latest/zk/org/zkoss/zul/ListModelArray.html</ref>
+
**Map - <javadoc>org.zkoss.zul.ListModelMap</javadoc>
:*Use ListModel methods to apply changes to the model.
+
**Object[] or Enum – <javadoc>org.zkoss.zul.ListModelArray</javadoc>
;Don’t:
+
*Use ListModel methods to apply changes to the model, including it's selection state.  
:*Use component methods to alter the view when using a model.
 
:*Mix model and manual entries in the same component.
 
  
==Understanding ZK scopes==
+
[[Image:Dndsmalltalk-cross-icon.png]] '''Don’t:'''
 +
*Use component methods to alter the view when using a model.
 +
*Mix model and manual entries in the same component.
 +
[https://github.com/zkoss-demo/zk-dos-and-donts/blob/master/src/main/java/local/support/zk_dos_and_donts/part1/CompVsModelComposer.java code examples]
 +
 
 +
=='''Understanding ZK scopes'''==
 
Scopes in ZK define the range affected by and action. For example, when creating an event queue, we need to define the scope of listeners affected by its events.
 
Scopes in ZK define the range affected by and action. For example, when creating an event queue, we need to define the scope of listeners affected by its events.
 
The basic scopes are DESKTOP, SESSION and APPLICATION. <ref>http://books.zkoss.org/wiki/ZK_Developer's_Reference/Event_Handling/Event_Queues#More_About_Scopes</ref>
 
The basic scopes are DESKTOP, SESSION and APPLICATION. <ref>http://books.zkoss.org/wiki/ZK_Developer's_Reference/Event_Handling/Event_Queues#More_About_Scopes</ref>
Line 31: Line 35:
 
SESSION represent the browser session. Assuming that the client uses cookies, it will match each tab in the browser.  
 
SESSION represent the browser session. Assuming that the client uses cookies, it will match each tab in the browser.  
 
DESKTOP roughly represents a unique browser tab. In specific cases, like Iframe, a tab can contain more than one desktop.
 
DESKTOP roughly represents a unique browser tab. In specific cases, like Iframe, a tab can contain more than one desktop.
When using events, choosing the right scope can lead to increased performances, reduced network activity and reduced memory consumption. It’s also work remembering that using any scope except Desktop will automatically activate server push.
+
When using events, choosing the right scope can lead to increased performances, reduced network activity and reduced memory consumption. It’s also worth remembering that using an event queue with any scope except Desktop will automatically activate server push.
;Do:
+
<br/>
:*Always use the smallest possible scope.
+
[[Image:Dndsmalltalk-check-icon.png]] '''Do:'''
:*Be careful when using session scope, as it will affect every desktops in the session.
+
*Always use the smallest possible scope.
:*Be extra careful when using application scope, as it will affect any desktops in the application.
+
*Be careful when using session scope, as it will affect every desktop in the session.
;Don’t:
+
*Be extra careful when using application scope, as it will affect any desktops in the application.
:*Use a scope broader than desktop unless you are sure that you need it.
 
:*Choose session or application if you do not want server push to be activated.
 
  
==Component belong to another desktop==
+
[[Image:Dndsmalltalk-cross-icon.png]] '''Don’t:'''
 +
*Use a scope broader than desktop unless you are sure that you need it.
 +
*Create an event queue using the session or application scopes if you do not want server push to be activated.
 +
[https://github.com/zkoss-demo/zk-dos-and-donts/blob/master/src/main/webapp/part1/2-scopes/iframeContent.zul code examples]
 +
 
 +
=='''Component belong to another desktop'''==
 
Saving a reference to a component can be a powerful way to keep track of changes, but there is one pitfall to avoid. ZK components are bound to a desktop, and cannot be passed around to another desktop or session.
 
Saving a reference to a component can be a powerful way to keep track of changes, but there is one pitfall to avoid. ZK components are bound to a desktop, and cannot be passed around to another desktop or session.
 
Choosing where to save or send the component reference is critical, as accessing it outside of its original desktop would cause exceptions in the best case, and corrupted views in the worst. To avoid this, always use desktop scope when passing around components, and only send values when serving a whole session or application.
 
Choosing where to save or send the component reference is critical, as accessing it outside of its original desktop would cause exceptions in the best case, and corrupted views in the worst. To avoid this, always use desktop scope when passing around components, and only send values when serving a whole session or application.
;Do:
 
:*Keep references of business objects, values between desktops if needed.
 
:*Use event queues for live data. Use session or application parameters for static data.
 
;Don’t:
 
:*Keep a reference to a view object such as a component as a session or application parameter.
 
:*Send a reference to a view object in an event queue with a scope is broader than desktop.
 
  
==Choosing @init, @load, @save, or @bind==
+
Trying to access a component belonging to another desktop will generate the following exception:
Using the MVVM data-binding annotations to link a view model and a view, you may use these four annotations.
+
<source>
 +
HTTP ERROR 500
 +
 
 +
Problem accessing /zk-dos-and-donts/part1/3-comp-and-desktop/. Reason:
 +
 
 +
    The parent and child must be in the same desktop: <Window o5JQ0>
 +
Caused by:
 +
 
 +
org.zkoss.zk.ui.UiException: The parent and child must be in the same desktop: <Window o5JQ0>
 +
</source>
 +
or
 +
<source>
 +
java.lang.IllegalStateException: Access denied: component, <Listcell z_27_b53>, belongs to another desktop: [Desktop g272]
 +
</source>
 +
<br/>
 +
[[Image:Dndsmalltalk-check-icon.png]] '''Do:'''
 +
*Send references of business objects or values between desktops if needed.
 +
*Use event queues for live data. Use session or application parameters for static data.
 +
 
 +
[[Image:Dndsmalltalk-cross-icon.png]] '''Don’t:'''
 +
*Keep reference to a view object such as a component as a session or application parameter.
 +
*Send a reference to a view object in an event queue with a scope is broader than desktop.
 +
[https://github.com/zkoss-demo/zk-dos-and-donts/blob/master/src/main/java/local/support/zk_dos_and_donts/part1/CompAndDesktopComposer.java code examples]
 +
 
 +
=='''Choosing @init, @load, @save, or @bind'''==
 +
Using the MVVM data-binding annotations to wire a view model and a view, you may use these four annotations.
 
*@init will load the value in the view once, but will not update it.<ref>http://books.zkoss.org/zk-mvvm-book/8.0/syntax/databindinginit.html</ref>
 
*@init will load the value in the view once, but will not update it.<ref>http://books.zkoss.org/zk-mvvm-book/8.0/syntax/databindinginit.html</ref>
 
*@load will load the value in the view, then updated it when the view model notify a change.<ref>http://books.zkoss.org/zk-mvvm-book/8.0/syntax/load.html</ref>
 
*@load will load the value in the view, then updated it when the view model notify a change.<ref>http://books.zkoss.org/zk-mvvm-book/8.0/syntax/load.html</ref>
Line 57: Line 83:
 
*@bind is basically @save plus @load. Values will be updated from and to the view model when necessary.<ref>http://books.zkoss.org/zk-mvvm-book/8.0/syntax/bind.html</ref>
 
*@bind is basically @save plus @load. Values will be updated from and to the view model when necessary.<ref>http://books.zkoss.org/zk-mvvm-book/8.0/syntax/bind.html</ref>
 
By expensiveness, they are ranked as follow: @init < @load | @save < @bind.
 
By expensiveness, they are ranked as follow: @init < @load | @save < @bind.
;Do:
+
<br/>
:*Choose the least expensive option for each binding.
+
[[Image:Dndsmalltalk-check-icon.png]] '''Do:'''
;Don’t:
+
*Choose the least expensive option for each binding.
:*Bind a value using @save or @bind on components whose value cannot be set by the user, such as label, etc.
+
 
:*Bind a value using @load or @bind on components whose value is never set on server side.
+
[[Image:Dndsmalltalk-cross-icon.png]] '''Don’t:'''
:*Use @load when @init is sufficient.
+
*Bind a value using @save or @bind on components whose value cannot be set by the user, such as label, etc.
 +
*Bind a value using @load or @bind on components whose value is never set on server side, such as a password entry field.
 +
*Use @load when @init is sufficient.
 +
[https://github.com/zkoss-demo/zk-dos-and-donts/blob/master/src/main/webapp/part1/4-wiring-efficiency/index.zul code examples]
 +
 
 +
=='''Notifying the whole ListModel on change'''==
 +
Speaking of models and data-binding, ListModels will automatically synchronize with the view on modification, such as adding or removing an element. This makes adding new entries in a complex control such as a grid very easy.
 +
However, it’s not always best to refresh the whole model after making a small update on one of its items. ListModels can actually update individual items, which can save a lot of resources and network traffic.
 +
<br/>
 +
[[Image:Dndsmalltalk-check-icon.png]] '''Do:'''
 +
*Bind a ListModel to a component using @init, unless you need to replace the whole model by a new object.
 +
*Use the ListModelList.notifyChange(…) [ZK 8.0.1.1], or .update(..) [ZK 8.0.0] method to update a single entry, or set the entry again to trigger a refresh instead of notifying the whole ListModel.
  
==Notifying the whole ListModel on change==
+
[[Image:Dndsmalltalk-cross-icon.png]] '''Don’t:'''
Speaking of models and data-binding, ListModels will automatically update the view after many actions, such as adding or deleting an element. This makes adding new entries in a complex control such as a grid very easy.
+
*Use @NotifyChange(“*”),  or BindUtils.postNotifyChange(…, …, …, "*"); unless there is no better option.
However, it’s not always best to refresh the whole model after making a small update on one of its items. ListModels can actually update individual items, which can save a lot of resources.
+
*Use @NotifyChange(“myListModel”) or BindUtils.postNotifyChange(…, …, …, "myListModel"); to update a single row.
;Do:
+
[https://github.com/zkoss-demo/zk-dos-and-donts/blob/master/src/main/java/local/support/zk_dos_and_donts/part1/NotifyOnChangeViewModel.java code examples]
:*Bind a ListModel to a component using @init, unless you need to replace the whole model by a new object.
 
:*Use the ListModelList.notifyChange(…) method to update a single entry, or set the entry again to trigger a refresh instead of notifying the whole model.
 
;Don’t:
 
:*Use @NotifyChange(“*”),  or BindUtils.postNotifyChange(…, …, …, "*"); unless there is no better option.
 
:*Use @NotifyChange(“myListModel”) or BindUtils.postNotifyChange(…, …, …, "myListModel"); to update a single row.
 
  
 
= References =  
 
= References =  

Latest revision as of 07:03, 18 March 2016

atthieu

Author
Matthieu Duchemin, Engineer, Potix Corporation
Date
March 2016
Version
ZK 8

ZK Do's and Don'ts Part 1

ZK Framework offers a lot of features to simplify the creation of Java-based web applications. Some of these features are not always well known. From time to time, we come across suboptimal implementation. Usually, it only takes a few simple steps to turn them simpler and easier. Those aren't necessarily broken or damaging, but improving them can have very positive effects with few changes or efforts. You will find here a few cases where ZK efficiency can be maximized.

Example project available here

Calling components directly when using a model

ZK offers default ListModel[1] implementations such as ListModelList. They provide an easy way to separate the view from the model. By providing a template or a renderer to control the appearance, and a model to handle the data. While delegating control to the model, it sometimes feels "easier" to act directly on a component. One would use grid.getRows().appendChild(..) to add a new row, or use listbox.setSelectedIndex() to set the selection state of a Listbox. If the components content is directly controlled by the application, this may be correct. However, if the content is controlled by a model, the model itself should perform these actions.
Dndsmalltalk-check-icon.png Do:

  • Use ListModels instead of basic collections when assigning a model to a component.
  • Use ListModel methods to apply changes to the model, including it's selection state.

Dndsmalltalk-cross-icon.png Don’t:

  • Use component methods to alter the view when using a model.
  • Mix model and manual entries in the same component.

code examples

Understanding ZK scopes

Scopes in ZK define the range affected by and action. For example, when creating an event queue, we need to define the scope of listeners affected by its events. The basic scopes are DESKTOP, SESSION and APPLICATION. [2] APPLICATION is very straightforward: it will affect every listeners on the whole application. SESSION represent the browser session. Assuming that the client uses cookies, it will match each tab in the browser. DESKTOP roughly represents a unique browser tab. In specific cases, like Iframe, a tab can contain more than one desktop. When using events, choosing the right scope can lead to increased performances, reduced network activity and reduced memory consumption. It’s also worth remembering that using an event queue with any scope except Desktop will automatically activate server push.
Dndsmalltalk-check-icon.png Do:

  • Always use the smallest possible scope.
  • Be careful when using session scope, as it will affect every desktop in the session.
  • Be extra careful when using application scope, as it will affect any desktops in the application.

Dndsmalltalk-cross-icon.png Don’t:

  • Use a scope broader than desktop unless you are sure that you need it.
  • Create an event queue using the session or application scopes if you do not want server push to be activated.

code examples

Component belong to another desktop

Saving a reference to a component can be a powerful way to keep track of changes, but there is one pitfall to avoid. ZK components are bound to a desktop, and cannot be passed around to another desktop or session. Choosing where to save or send the component reference is critical, as accessing it outside of its original desktop would cause exceptions in the best case, and corrupted views in the worst. To avoid this, always use desktop scope when passing around components, and only send values when serving a whole session or application.

Trying to access a component belonging to another desktop will generate the following exception:

HTTP ERROR 500

Problem accessing /zk-dos-and-donts/part1/3-comp-and-desktop/. Reason:

    The parent and child must be in the same desktop: <Window o5JQ0>
Caused by:

org.zkoss.zk.ui.UiException: The parent and child must be in the same desktop: <Window o5JQ0>

or

java.lang.IllegalStateException: Access denied: component, <Listcell z_27_b53>, belongs to another desktop: [Desktop g272]


Dndsmalltalk-check-icon.png Do:

  • Send references of business objects or values between desktops if needed.
  • Use event queues for live data. Use session or application parameters for static data.

Dndsmalltalk-cross-icon.png Don’t:

  • Keep reference to a view object such as a component as a session or application parameter.
  • Send a reference to a view object in an event queue with a scope is broader than desktop.

code examples

Choosing @init, @load, @save, or @bind

Using the MVVM data-binding annotations to wire a view model and a view, you may use these four annotations.

  • @init will load the value in the view once, but will not update it.[3]
  • @load will load the value in the view, then updated it when the view model notify a change.[4]
  • @save will not load anything in the view, but will save the values from the view into the view model when updated.[5]
  • @bind is basically @save plus @load. Values will be updated from and to the view model when necessary.[6]

By expensiveness, they are ranked as follow: @init < @load | @save < @bind.
Dndsmalltalk-check-icon.png Do:

  • Choose the least expensive option for each binding.

Dndsmalltalk-cross-icon.png Don’t:

  • Bind a value using @save or @bind on components whose value cannot be set by the user, such as label, etc.
  • Bind a value using @load or @bind on components whose value is never set on server side, such as a password entry field.
  • Use @load when @init is sufficient.

code examples

Notifying the whole ListModel on change

Speaking of models and data-binding, ListModels will automatically synchronize with the view on modification, such as adding or removing an element. This makes adding new entries in a complex control such as a grid very easy. However, it’s not always best to refresh the whole model after making a small update on one of its items. ListModels can actually update individual items, which can save a lot of resources and network traffic.
Dndsmalltalk-check-icon.png Do:

  • Bind a ListModel to a component using @init, unless you need to replace the whole model by a new object.
  • Use the ListModelList.notifyChange(…) [ZK 8.0.1.1], or .update(..) [ZK 8.0.0] method to update a single entry, or set the entry again to trigger a refresh instead of notifying the whole ListModel.

Dndsmalltalk-cross-icon.png Don’t:

  • Use @NotifyChange(“*”), or BindUtils.postNotifyChange(…, …, …, "*"); unless there is no better option.
  • Use @NotifyChange(“myListModel”) or BindUtils.postNotifyChange(…, …, …, "myListModel"); to update a single row.

code examples

References


Comments



Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License.