Employment/Purpose
Here we describe how to embed ZK component(s) as a native element of a foreign framework. For example, how ZK components can be embedded as a native JSF component. It allows application developers to use the native element without knowing the existence of ZK.
For the sake of description, we call it the embedded component.
Note: If it is OK for your developers to work on ZUL directly, it is more convenient and powerful to use the inclusion (such as <jsp:include>) or ZK JSP > Tags, and you don’t have to wrap them into a native element.
Prerequisite
DOCTYPE
To use ZK components correctly, the pages generated by the foreign framework (JSP, JSF…) must generate the doc type as follows.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
Browser Cache
Though optional, it is suggested to disable the browser to cache the result page. It can be done as follows.
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="-1" />
Embed a component directly
The simplest way to embed is to invoke
when it is time to output the content of the native element.
For example, if you are implementing a JSP tag, then you can invoke the
render method in doTag()
as follows.
public void doTag() throws JspException, IOException {
//prepare variables
final JspContext jspctx = getJspContext();
final PageContext pgctx = Jsps.getPageContext(jspctx);
final ServletContext svlctx = pgctx.getServletContext();
final HttpServletRequest request = (HttpServletRequest)pgctx.getRequest();
final HttpServletResponse response = (HttpServletResponse)pgctx.getResponse();
//create components
Listbox listbox = new Listbox();
listbox.appendChild(new Listitem("Item 1"));
listbox.appendChild(new Listitem("Item 2"));
//render the result
final StringWriter out = new StringWriter();
Renders.render(svlctx, request, response, listbox, null, out);
getJspBody().invoke(out);
}
Embed by implementing a richlet
If you want to have more control, such as applying a composer provided
by users or creating components from a ZUL page, you could implement a
richlet (
instead.
Renders.render(svlctx, request, response,
new GenericRichlet() {
public void service(Page page) throws Exception {
//execution is ready
//... do whatever you want
Window main = new Window();
main.setPage(page); //associate to the page
Executions.createComponents("/WEB-INF/template/foo.zul", main, null);
composer.doAfterCompose(main); //assume user assigned a composer
}
}, null, out);
where we use org.zkoss.zk.ui.GenericRichlet to simplify the implementation of a richlet.
Example
Embed as a native JSF component
ZK Component as a native JSF component can be easily achieved by wrapping it as a custom JSF component 1 and rendering it in Render Response Phase of JSF lifecycle by invoking
@FacesComponent(value = "window")
public class WindowTag extends UIComponentBase {
private static final Log log = Log.lookup(WindowTag.class);
private Window window;
public void encodeBegin(FacesContext context) throws IOException {
ServletContext svlctx = (ServletContext)context.getExternalContext().getContext();
HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();
ResponseWriter responseWriter = context.getResponseWriter();
try {
Renders.render(svlctx, request,response,
new GenericRichlet() {
public void service(Page page) throws Exception {
window = new Window();
window.setPage(page);
applyProperties();
doAfterCompose();
}
}, null, responseWriter);
} catch (ServletException e) {
throw new IOException(e.getMessage());
}
}
/** apply ZK component properties as retrieved from JSF custom component tag */
private void applyProperties() {
Map<String, Object> attrs = getAttributes();
Set<String> attrNames = attrs.keySet();
for (Iterator iterator = attrNames.iterator(); iterator.hasNext();) {
String attrName = (String) iterator.next();
if(!"apply".equals(attrName)) {
try {
Property.assign(window, attrName, attrs.get(attrName).toString());
} catch(PropertyNotFoundException pnfe) {
log.debug(pnfe.getMessage());
}
}
}
}
/** apply composer by calling doAfterCompose after ZK component is composed */
private void doAfterCompose() throws Exception {
Object o = getAttributes().get("apply");
if(o instanceof String) {
o = Classes.newInstanceByThread(o.toString());
}
if(o instanceof Composer) {
((Composer)o).doAfterCompose(window);
}
}
....
}
Version History
Version | Date | Content |
---|---|---|
5.0.5 | September 2010 | org.zkoss.zkplus.embed.Renders was introduced to simplify the making of a native element for a foreign framework. |