ZK dos and donts part1"

From Documentation
 
(8 intermediate revisions by 2 users not shown)
Line 6: Line 6:
  
 
=ZK Do's and Don'ts Part 1=
 
=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 take 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 without much changes or efforts.
+
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.
 
You will find here a few cases where ZK efficiency can be maximized.
  
Line 13: Line 13:
 
=='''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.
 
<br/>
 
<br/>
 
[[Image:Dndsmalltalk-check-icon.png]] '''Do:'''
 
[[Image:Dndsmalltalk-check-icon.png]] '''Do:'''
 
*Use ListModels instead of basic collections when assigning a model to a component.
 
*Use ListModels instead of basic collections when assigning a model to a component.
**List – ListModelList <ref>https://www.zkoss.org/javadoc/latest/zk/org/zkoss/zul/ListModelList.html</ref>
+
**List – <javadoc>org.zkoss.zul.ListModelList</javadoc>
**Set – ListModelSet <ref>https://www.zkoss.org/javadoc/latest/zk/org/zkoss/zul/ListModelSet.html</ref>
+
**Set – <javadoc>org.zkoss.zul.ListModelSet</javadoc>
**Map - ListModelMap <ref>https://www.zkoss.org/javadoc/latest/zk/org/zkoss/zul/ListModelMap.html</ref>
+
**Map - <javadoc>org.zkoss.zul.ListModelMap</javadoc>
**Object[] or Enum – ListModelArray <ref>https://www.zkoss.org/javadoc/latest/zk/org/zkoss/zul/ListModelArray.html</ref>
+
**Object[] or Enum – <javadoc>org.zkoss.zul.ListModelArray</javadoc>
 
*Use ListModel methods to apply changes to the model, including it's selection state.  
 
*Use ListModel methods to apply changes to the model, including it's selection state.  
  
Line 28: Line 28:
 
*Mix model and manual entries in the same component.
 
*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]
 
[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'''==
 
=='''Understanding ZK scopes'''==
Line 36: 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 an event queue with 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.
 
<br/>
 
<br/>
 
[[Image:Dndsmalltalk-check-icon.png]] '''Do:'''
 
[[Image:Dndsmalltalk-check-icon.png]] '''Do:'''
 
*Always use the smallest possible scope.
 
*Always use the smallest possible scope.
*Be careful when using session scope, as it will affect every desktops in the session.
+
*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.
 
*Be extra careful when using application scope, as it will affect any desktops in the application.
  
 
[[Image:Dndsmalltalk-cross-icon.png]] '''Don’t:'''
 
[[Image:Dndsmalltalk-cross-icon.png]] '''Don’t:'''
 
*Use a scope broader than desktop unless you are sure that you need it.
 
*Use a scope broader than desktop unless you are sure that you need it.
*Create an event queue using the session or application or application scopes if you do not want server push to be activated.
+
*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]
 
[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'''==
 
=='''Component belong to another desktop'''==
Line 63: Line 61:
  
 
org.zkoss.zk.ui.UiException: The parent and child must be in the same desktop: <Window o5JQ0>
 
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>
 
</source>
 
<br/>
 
<br/>
Line 73: Line 75:
 
*Send a reference to a view object in an event queue with a scope is broader than desktop.
 
*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]
 
[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'''==
 
=='''Choosing @init, @load, @save, or @bind'''==
Line 90: Line 91:
 
*Bind a value using @load or @bind on components whose value is never set on server side, such as a password entry field.
 
*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.
 
*Use @load when @init is sufficient.
[https://github.com/zkoss-demo/zk-dos-and-donts/blob/master/src/main/java/local/support/zk_dos_and_donts/part1/WiringEfficiencyViewModel.java code examples]
+
[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'''==
 
=='''Notifying the whole ListModel on change'''==

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.