ZK Spreadsheet as a native JSF component

From Documentation
DocumentationSmall Talks2010SeptemberZK Spreadsheet as a native JSF component
ZK Spreadsheet as a native JSF component

Author
Ashish Dasnurkar, Engineer, Potix Corporation
Date
September 20, 2010
Version
Applicable to JSF 2.0 or later.
ZK 5.0.5 or later.

Introduction

ZK Spreadsheet

ZK Spreadsheet is 1st embeddable Ajax spreadsheet for Java web applications. It enables Ajax applications to deliver the rich functionality of Excel® within browsers using pure Java. With embeddable Excel® functionality, developers are able to create collaborative and dynamic enterprise applications at minimal cost. For more information see ZK Spreadsheet product page. You can also see ZK Spreadsheet in action by visiting our ZK Spreadsheet Live demo here

ZK Spreadsheet JSF component

ZK Spreadsheet with its embeddable Excel functionality is now available to JSF application developers.ZK Spreadsheet can now be embedded as a JSF native component in JSF 2.0 applications. The way to embed ZK Spreadsheet on JSF 2.0 facelets is same as for any other JSF components. First specify ZK Spreadsheet component namespace URI http://www.zkoss.org/jsf/zss declaration along with other JSF namespace declarations as shown below

<html xmlns="http://www.w3.org/1999/xhtml"
   xmlns:ui="http://java.sun.com/jsf/facelets"
   xmlns:h="http://java.sun.com/jsf/html"
   xmlns:f="http://java.sun.com/jsf/core"
   xmlns:zk="http://www.zkoss.org/jsf/zss">
   .
   .
   .
   </html>

and embed ZK Spreadsheet in a JSF 2.0 facelet using spreadsheet tag as shown below

       <zk:spreadsheet src="Temiesheet1.xls" apply="${spreadsheetController}" />

ZK spreadsheet JSF component tag supports all the properties that are supported by ZK Spreasdsheet ZUL component tag. Below is another example of using some more spreadsheet component tag properties

         <zk:spreadsheet id="myspreadsheet" src="Timesheet1.xls" maxrows="100" maxcolumns="20" width="100%" height="100%" apply="${spreadsheetController}"></zk:spreadsheet>

this and couple of simple configuration steps as explained below is all you need to start using ZK Spreadsheet in your JSF application.

Setting up ZK Spreadsheet JSF component

  • Download ZK 5.0.5 or later release binaries and config them to be used as your JSF web application libraries by either directly copying into WEB-INF/lib or putting them on your web application classpath
  • Download ZK Spreadsheet 2.0 Beta3 or later release binaries and config it to be used as your JSF web application library by either directly copying into WEB-INF/lib or putting them on your web application classpath
  • Add org.zkoss.zk.au.http.DHtmlUpdateServlet and its mapping into web.xml as shown below
  <servlet>
  	<description>
  	The asynchronous update engine for ZK</description>
  	<servlet-name>auEngine</servlet-name>
  	<servlet-class>
  	org.zkoss.zk.au.http.DHtmlUpdateServlet</servlet-class>
  </servlet>
  <servlet-mapping>
  	<servlet-name>auEngine</servlet-name>
  	<url-pattern>/zkau/*</url-pattern>
  </servlet-mapping>
  • and finally add ZK Spreadsheet JSF component taglib into the web.xml as shown below
	<context-param>
		<param-name>javax.faces.FACELETS_LIBRARIES</param-name>
		<param-value>/WEB-INF/jsfzss-taglib.xml</param-value>
	</context-param>

Example

Let's see it in Action in the demo below.

and here is the complete source code for index.xhtml file.

<html xmlns="http://www.w3.org/1999/xhtml"
   xmlns:ui="http://java.sun.com/jsf/facelets"
   xmlns:h="http://java.sun.com/jsf/html"
   xmlns:f="http://java.sun.com/jsf/core"
   xmlns:zk="http://www.zkoss.org/jsf/zss">    
   <h:head>
        <title>ZK Spreadsheet in JSF Demo</title>
    </h:head>
    <h:body>
        <h:form>
            <h:outputText value="Cell"></h:outputText>
            <h:inputText id="cellReference" value="${myBean.cellReference}"></h:inputText>
            
            <h:commandButton id="show" value="Show" actionListener="${myBean.showCellValue}">
            	<f:ajax render="cvalue" execute="@all"></f:ajax>
            </h:commandButton>
            
            <h:outputText value="Value"></h:outputText>
            <h:inputText id="cvalue" value="${myBean.cvalue}"></h:inputText>
            
            <h:commandButton id="set" value="Set" onclick="jsf.ajax.request(this, event, {execute:'@all'}); return false;" actionListener="${myBean.setCellText}">
            </h:commandButton>
            
            <zk:spreadsheet id="myspreadsheet" src="Timesheet1.xls" maxrows="100" maxcolumns="20" width="100%" height="100%" 
                     binding="${myBean.myBeanSpreadsheet}" apply="${myBean}">
             </zk:spreadsheet>

        </h:form>
    </h:body>
 </html>

Example above has two inputText JSF components with respective outputText labels for Cell and Value. It also has three commandButton components Show, Set & Print to Pdf followed by ZK Spreadsheet JSF component.

Retrieving ZK Spreadsheet data

In the demo above I demonstrated two use cases. First use case is to get value for a specific ZK spreadsheet cell as indicated by Cell input text boxes and display it in the cvalue input textbox when Show command button is clicked. Here is the peice of code from index.xhtml that makes it work.

        ...
        <h:form>
            <h:outputText value="Cell"></h:outputText>
            <h:inputText id="cellReference" value="${myBean.cellReference}"></h:inputText>
            
            <h:commandButton id="show" value="Show" actionListener="${myBean.showCellValue}">
            	<f:ajax render="cvalue" execute="@all"></f:ajax>
            </h:commandButton>
            
            <h:outputText value="Value"></h:outputText>
            <h:inputText id="cvalue" value="${myBean.cvalue}"></h:inputText>
            ... 

        </h:form>
        ...

As you can see cellReference inputText component is value bound to cellReference property of MyBean backing bean. Clicking commandButton Show invokes backing bean method showCellValue. Another important thing to note is I have used component binding of JSF to bind ZK Spreadsheet JSF component to myBeanSpreasheet property of MyBean as shown below.

<zk:spreadsheet id="myspreadsheet" src="Timesheet1.xls" maxrows="100" maxcolumns="20" width="100%" height="100%" 
             binding="${myBean.myBeanSpreadsheet}" apply="${myBean}">
</zk:spreadsheet>

... and here is the code for MyBean method showCellValue.

public void showCellValue(ActionEvent e) {
        Range range = Ranges.range(myBeanSpreadsheet.getSpreadsheet().getSelectedSheet(), cellReference);
        FormatText ft = range.getFormatText();
        if (ft != null && ft.isCellFormatResult()) {
                setCvalue(ft.getCellFormatResult().text);
        } else {
                final RichTextString rstr = range == null ? null : range.getRichEditText();
                setCvalue(rstr != null ? rstr.getString() : "");
        }
}

So here I brief a little bit the process sequence of this use case

  1. End user enters cell reference value in cellReference input textbox.
  2. End user clicks Show commandButton which causes f:ajax to initiate an ajax request.
  3. execute="@all" causes JSF to transfer end user entered value for cellReference input textbox to cellReference properties of MyBean backing bean.
  4. actionListener for commandButton Show is invoked i.e. showCellValue method
  5. showValueCell updates backing bean property cvalue with the value of ZK Spreadsheet cell indentified by cellReference retrieved using ZK Spreadsheet APIs such as Ranges.range, Range.getFormatText etc
  6. render="cvalue" rerenders cvalue inputTextbox component and populates it with the updated cvalue backing bean property value.

Setting ZK Spreadsheet data and properties

Second use case is to set value entered in cvalue inputText component into a specific ZK spreadsheet cell as indicated by Cell input text boxes. Here is the piece of code from index.xhtml that make it work

<h:commandButton id="set" value="Set" onclick="jsf.ajax.request(this, event, {execute:'@all'}); return false;" actionListener="${myBean.setCellText}">
</h:commandButton>

Clicking commandButton Set invokes MyBean method setCellText by initiating an Ajax request using jsf.ajax.request introduced in JSF 2.0. Let's take a look at setCellText method.

public void setCellText(ActionEvent e) throws IOException {

        ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
        ServletContext svlctx = (ServletContext) ec.getContext();
        HttpServletRequest request = (HttpServletRequest) ec.getRequest();
        HttpServletResponse response = (HttpServletResponse) ec.getResponse();

        Bridge bridge = Bridge.start(svlctx, request, response,
                        myBeanSpreadsheet.getSpreadsheet().getDesktop());
        try {
                
                final Range range = Ranges.range(myBeanSpreadsheet.getSpreadsheet().getSelectedSheet(), cellReference);
                range.setEditText(cvalue);
                
                //Send back bridge.getResult() with the response writer (eval)
                PartialResponseWriter responseWriter = FacesContext.getCurrentInstance().getPartialViewContext().getPartialResponseWriter();
                responseWriter.startDocument();
                responseWriter.startEval();
                responseWriter.write(bridge.getResult());
                responseWriter.endEval();
                responseWriter.endDocument();
                responseWriter.flush();
                responseWriter.close();
        
        } finally {
                bridge.close();
        }
}

As you can see since this is an Ajax action event of JSF I initiate Bridge [1] that allows me to start a ZK execution and update ZK component(s) state. Bridge also has convenient method to retrieve javascript required to update ZK Component client side. Since this is happening in JSF Ajax channel I use JSF PartialResponseWriter to send back javascript retrieved from Bridge to update ZK Spreadsheet client side and have it evaluated at the client by JSF jsf.ajax.response.

So here I brief a little bit the process sequence of this use case

  1. End user enters cell reference value in cellReference input textbox.
  2. End user clicks Set commandButton which causes jsf.ajax.request to initiate an ajax request.
  3. {execute:'@all'} parameter to jsf.ajax.request causes JSF to transfer end user entered value for cell reference & value input textboxes to cellReference & cvalue properties of MyBean backing bean.
  4. actionListener for commandButton Set is invoked i.e. setCellText method
  5. setCellText uses Bridge to start a ZK execution and updates ZK Spread cell value. It also constructs partial response to be processed by jsf.ajax.response to update ZK Spreadsheet at the client
  6. On receiving partial response jsf.ajax.response evaluates javascript and ZK Spreadsheet cell is updated with value entered by user in cvalue inputTextbox.

In similar way i.e. using component binding of JSF developers can gain access to ZK Spreadsheet component and use Bridge & ZK Spreadsheet APIs to access/modify its data and visual properties.


  1. A new feature ZK Developer's Reference: Integration in ZK 5.0.5 release that allows to start execution in foreign Ajax channel

What's more

In addtion to embedding and interacting with ZK Spreadsheet within JSF environment, JSF developers who are familier with ZK can also leverage ZK component lifecycle events and ZK MVC to manage ZK compoents/events within JSF environment. For example you can use apply attribute of ZK Spreadsheet to apply a controller to manage ZK Spreadsheet component and its events. Aply attribute value could be a fully qualified class name or an EL expression that evaluates to a controller instance.

Summary

In this article I introduced how ZK Spreadsheet can be embedded as a native JSF component in a JSF 2.0 application. I also described how other JSF components can intereact with ZK Spreadsheet in JSF environment.

Download

Download ZK Spreadsheet JSF Component Demo (.war file)

References

  1. ZK Spreadsheet
  2. JavaServer Faces
  3. jsf.ajax javascript docs
  4. MVC in ZK



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