Property Rendering
If a state (aka., a property) of a component will cause the peer widget to have a different behavior or visual appearance, the state has to be sent to the widget to ensure the consistency.
There are two situations a component has to send the states to the client.
- Render All Properties When Attached
- A component has to render all properties when it is attached to a page at the first time
- Dynamic Update a Property
- A component has to send the new value of a property when it is changed dynamically.
Notice that this section describes how to synchronize states of a component to the widget. To synchronize states back to a component, refer to the AU Requests section.
Render All Properties When Attached
When ZK is about rendering a new-attached component to the client (by new-attached we mean just attached to a desktop), ComponentCtrl.redraw(Writer) is called to render the component, including the widget's class name, all properties, event listeners and so on.
However, you don't have to implement ComponentCtrl.redraw(Writer) from ground up. AbstractComponent provides a default implementation, so you could override AbstractComponent.renderProperties(ContentRenderer) instead.
renderProperties
Overriding AbstractComponent.renderProperties(ContentRenderer) is straightforward: call back super.renderProperties
to render inherited properties, and then call one of the render
methods to render the properties of the component.
protected void renderProperties(ContentRenderer renderer)
throws IOException {
super.renderProperties(renderer);
render(renderer, "myProp", _myProp);
//...
}
Notice that the render methods of AbstractComponent will ignore null, empty string, and false automatically. Thus, the if statement in the following example is redundant.
if (value != null && value .length() != 0) //redundant since render will check
render(renderer, "name", value); //does nothing if null or empty
On the other hand, if you want to render null and an empty string, you shall invoke the render methods of ContentRenderer, such as
render.render("name", value);
redrawChildren
After calling renderProperties
, redraw
calls AbstractComponent.redrawChildren(Writer) to render the properties of children recursively.
Here is the calling sequence of the default implementation of AbstractComponent.redraw(Writer):
renderProperties(new JsContentRenderer());
redrawChildren(out);
Render Special Properties
ZK Client Engine supports several special properties to provide extra functionality, such as late evaluation and so on.
z_al
Specifies a map of properties that shall be evaluated after all script files are loaded.
Example:
protected void renderProperties(org.zkoss.zk.ui.sys.ContentRenderer renderer)
throws java.io.IOException {
//assume js is the JavaScript code snippet
renderer.renderDirectly("z_al", "{constraint:function(){\nreturn "+js+";}}");
}
Notice that the value of z_al is a JavaScript map of properties that will be evaluated after loading corresponding JavaScript files. Moreover, the value of the map is a function that return the object being assigned with.
z_ea
Specifies the property name whose value must be retrieved from the DOM element with the same UUID.
It is used to create a ZK application that can be crawled by search engines.
Example,
renderer.render("z_ea", "content");
Then, the content property's value will become the inner HTML of the DOM element with the same UUID.
If the content has to decode first (from < to <, see zUtl#decodeXML), prefix the property name with '$'.
renderer.render("z_ea", "$content");
z_pk
Specifies a list of packages separated by comma that shall be loaded before creating widgets.
Example,
renderer.render("z_pk", "com.foo,com.foo.more");
Enforce ZK Update Engine to Redraw a Component
A component can enforce ZK Update Engine to redraw a component by calling Component.invalidate(). Once called, the peer widget will be removed, and a new peer widget will be created to represent the new content. Thus, all modification to the widget at client will be lost if not preserved (or synchronized back) to the server.
Also notice that Component.redraw(Writer) won't be called immediately. Rather, ZK Update Engine will accumulate all updates, and then optimize the number of commands (AU responses) that need to be sent.
Dynamic Update a Property
When the application modifies a property that affects the peer widget, a component has to send the updated value to the peer widget. It is done by calling smartUpdate
of AbstractComponent
. For example,
public void setValue(String value) {
if (!_value.equals(value)) {
_value = value;
smartUpdate("value", _value);
}
}
If the peer widget was created in the previous request (i.e., the component was attached to page), the invocation of smartUpdate
actually cause the peer widget's setter of the specified properties being called. In the above example, setValue
will be called at the client.
On the other hand, if a component is not yet attached to a page, smartUpdate
does nothing (since the peer widget doesn't exist). If invalidate
was called, smartUpdate
does nothing and previous invocation of smartUpdate
of the same request are ignored (since the peer widget will be removed and re-created).
Deferred Property Value
Sometimes the value is not ready when smartUpdate
is called, and it is better to generate in the rendering phase. For example, encodeURL
is better to be called in the rendering phase[1]. To defer the evaluation of a value, you can implement the org.zkoss.zk.ui.util.DeferedValue
interface.
public void setSrc(String src) {
if (!Objects.equals(_src, src)) {
_src = src;
smartUpdate("src", new EncodedURL());
}
}
private class EncodedURL implements DeferedValue {
public Object getValue() {
return getDesktop().getExecution().encodeURL(_src);
}
}
- ↑ It is because
smartUpdate
is usually called in an event listener, which is, by default, running at the event thread. Meanwhile, WebSphere 5 doesn't allow callingencodeURL
other than the servlet thread. The alternative solution is to disable the use of event thread.
Version History
Version | Date | Content |
---|---|---|