Using Spreadsheet JSF Component"

From Documentation
m
m (correct highlight (via JWB))
 
(10 intermediate revisions by 3 users not shown)
Line 19: Line 19:
  
 
= Create a JSF Page =
 
= Create a JSF Page =
Spreadsheet can be embedded in a JSF page in the same way as JSF standard components. First specify ZK Spreadsheet component namespace URI <tt>http://www.zkoss.org/jsf/zss</tt> declaration along with other JSF namespace declarations and you can use the tag like <tt><zssjsf:spreadsheet/></tt>. If we want to interact with Spreadsheet in JSF AJAX tag, we should also put a <tt><zssjsf:update/></tt> component which is invisible in the browser in on the same page to process ZK AU response.  
+
Spreadsheet can be embedded in a JSF page in the same way as JSF standard components. First specify ZK Spreadsheet component namespace URI <code>http://www.zkoss.org/jsf/zss</code> declaration along with other JSF namespace declarations and you can use the tag like <code><zssjsf:spreadsheet/></code>. If we want to interact with Spreadsheet in JSF AJAX tag, we should also put a <code><zssjsf:update/></code> component which is invisible in the browser in on the same page to process ZK AU response.  
 
Let's see the JSF page of our example application.
 
Let's see the JSF page of our example application.
  
 
'''app4l.xhtml'''
 
'''app4l.xhtml'''
<source lang='xml' high='5,10, 16,17,18, 25,29,34'>
+
<source lang='xml' highlight='5,10, 16,17,18, 25,29,35'>
 
<?xml version="1.0" encoding="UTF-8"?>
 
<?xml version="1.0" encoding="UTF-8"?>
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"  
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"  
Line 47: Line 47:
 
showContextMenu="true" showSheetbar="true"/>
 
showContextMenu="true" showSheetbar="true"/>
 
<h:panelGrid columns="3">
 
<h:panelGrid columns="3">
<h:commandButton value="Reset" action="#{applicationForLeave.doReset}" >
+
<h:commandButton value="Reset"
<f:ajax execute="@all" render="msg zkupdate" />
+
action="#{applicationForLeave.doReset}" >
</h:commandButton>
+
<f:ajax execute="@all" render="msg zkupdate"/>
+
</h:commandButton>
<h:commandButton value="Ok" action="#{applicationForLeave.doOk}" >
+
<h:commandButton value="Ok"
 +
action="#{applicationForLeave.doOk}">
 
<f:ajax execute="@all" render="msg zkupdate" />
 
<f:ajax execute="@all" render="msg zkupdate" />
 
</h:commandButton>
 
</h:commandButton>
Line 63: Line 64:
 
</source>
 
</source>
 
* Line 16: ZK Spreadsheet JSF component tag supports all the properties that are supported by Spreadsheet ZUL component tag.
 
* Line 16: ZK Spreadsheet JSF component tag supports all the properties that are supported by Spreadsheet ZUL component tag.
* Line 17: The <tt>book</tt> attribute is only available on JSF component which is used to bind a <javadoc directory="zss">org.zkoss.zss.api.model.Book</javadoc> to spreadsheet from a managed bean.
+
* Line 17: The <code>book</code> attribute is used to bind a <javadoc directory="zss">org.zkoss.zss.api.model.Book</javadoc> to spreadsheet from a managed bean.
* Line 18: The <tt>actionBridge</tt> attribute is only available on JSF component which is used to set an <javadoc directory="zss">org.zkoss.zss.jsf.ActionBridge</javadoc> to a managed bean. This object will be explained in next section.
+
* Line 18: The <code>actionBridge</code> attribute is only available on Spreadsheet JSF component which is used to set an <javadoc directory="zss">org.zkoss.zss.jsf.ActionBridge</javadoc> to a managed bean. This object will be explained in next section.
* Line 25, 29: We use JSF's AJAX tag to trigger event handler methods defined in our managed bean. The component ID in <tt>execute</tt> attribute must include <tt>zssjsf:spreadsheet</tt> ID, and here we use <tt>@all</tt> just for convenience.
+
* Line 25, 29: We use JSF's AJAX tag to trigger event handler methods defined in our managed bean. The component ID in <code>execute</code> attribute must include <code>zssjsf:spreadsheet</code> ID, and here we use <code>@all</code> just for convenience. The <code>render</code> attribute must include  <code>zssjsf:update</code> ID.
The <tt>render</tt> attribute must include  <tt>zssjsf:update</tt> ID.
+
* Line 35: The <code>update</code> is another JSF component provided by ZK Spreadsheet which is responsible for processing ZK AU response.
* Line 34: The <tt>update</tt> is another JSF component provided by ZK Spreadsheet which is responsible for processing ZK AU response.
 
  
 
= Managed Bean =
 
= Managed Bean =
It's a standard practice to bind a JSF component with a managed bean which contains data model and business logic. Spreadsheet JSF component obtains <tt>Book</tt> object from attribute <tt>book</tt> and set <tt>ActionBridge</tt> to a managed bean's <tt>actionBridge</tt>
+
It's a standard practice to bind a JSF component with a managed bean which contains data model and business logic. Spreadsheet JSF component obtains <code>Book</code> object from attribute <code>book</code> and set <code>ActionBridge</code> to a managed bean's <code>actionBridge</code>
  
<source lang='java' high='12, 20, 56'>
+
<source lang='java' highlight='12, 20, 56'>
 
@ManagedBean
 
@ManagedBean
 
@RequestScoped
 
@RequestScoped
Line 135: Line 135:
 
</source>
 
</source>
 
* Line 12,20: Import a file for a Spreadsheet.
 
* Line 12,20: Import a file for a Spreadsheet.
* Line 56: The <tt> actionBridge</tt> will be set by Spreadsheet JSF component.
+
* Line 56: The <code> actionBridge</code> will be set by Spreadsheet JSF component.
  
 
= Implement Event Handler Method =  
 
= Implement Event Handler Method =  
In JSF, we can use the syntax below to invoke an event handler method, <tt>doReset()</tt>, of a managed bean ( <tt>applicationForLeave</tt>) in AJAX request.
+
In JSF, we can use the syntax below to invoke an event handler method, <code>doReset()</code>, of a managed bean ( <code>applicationForLeave</code>) in AJAX request.
 
<source lang='xml'>
 
<source lang='xml'>
 
<h:commandButton value="Reset" action="#{applicationForLeave.doReset}" >
 
<h:commandButton value="Reset" action="#{applicationForLeave.doReset}" >
Line 145: Line 145:
 
</source>
 
</source>
  
Because of accessing ZK components like Spreadsheet needs to be in a ZK execution, we can use <tt>ActionBridge</tt> to help us. One new <tt>ActionBridge</tt> object is provided by Spreadsheet JSF component for each request to a managed bean via setter. All we have to do is to specify in <tt>actionBridge</tt> attribute with a managed bean's property like:
+
Because of accessing ZK components like Spreadsheet needs to be in a ZK execution, we can use <code>ActionBridge</code> to help us. One new <code>ActionBridge</code> object is provided by Spreadsheet JSF component for each request to a managed bean via setter. All we have to do is to specify in <code>actionBridge</code> attribute with a managed bean's property like:
 
<source lang='xml'>
 
<source lang='xml'>
<zssjsf:spreadsheet id="myzss" actionBridge="#{applicationForLeave.actionBridge}"  .../>
+
<zssjsf:spreadsheet id="myzss"
 +
actionBridge="#{applicationForLeave.actionBridge}"  .../>
 
</source>
 
</source>
  
Then, we can use this <tt>ActionBridge</tt> to execute our business logic: reset and check cells.
+
Then, we can use this <code>ActionBridge</code> to execute our business logic: reset and check cells.
  
  
 
== Handling Spreadsheet Data Model ==
 
== Handling Spreadsheet Data Model ==
Inside <tt>ActionBridge.execute()</tt>, you can use those APIs we mentioned in [[ZK_Spreadsheet_Essentials_3/Working_with_Spreadsheet/Handling_Data_Model| Handling Data Model]] to implement your business logic. In our example, we use <javadoc directory="zss">org.zkoss.zss.api.Range</javadoc> to set cell edit text and get value from cells.
+
Inside <code>ActionBridge.execute()</code>, you can use those APIs we mentioned in [[ZK_Spreadsheet_Essentials_3/Working_with_Spreadsheet/Handling_Data_Model| Handling Data Model]] to implement your business logic. In our example, we use <javadoc directory="zss">org.zkoss.zss.api.Range</javadoc> to set cell edit text and get value from cells.
  
  
  
==Reset Cells ==
+
==doReset() ==
The usage of <tt>ActionBridge</tt> is to call its <tt>execute()</tt> with an <javadoc directory="zss">org.zkoss.zss.jsf.Action</javadoc> object and we implement our business logic in <tt>Action</tt>'s <tt>execute()</tt> method with those APIs mentioned in [[ZK Spreadsheet Essentials 3/Working with Spreadsheet| previous sections]]. In "reset cells" case, we use <tt>Range</tt> to clear cell text.
+
The usage of <code>ActionBridge</code> is to call its <code>execute()</code> with an <javadoc directory="zss">org.zkoss.zss.jsf.Action</javadoc> object and we implement our business logic in <code>Action</code>'s <code>execute()</code> method with those APIs mentioned in [[ZK Spreadsheet Essentials 3/Working with Spreadsheet| previous sections]]. In "reset cells" case, we use <code>Range</code> to clear cell text.
  
<source lang='java' high='10,11'>
+
<source lang='java' highlight='10,11'>
 
@ManagedBean
 
@ManagedBean
 
@RequestScoped
 
@RequestScoped
Line 201: Line 202:
 
}
 
}
 
</source>
 
</source>
* Line 10: Handling an events by passing an <tt>Action</tt> object implemented with your business logic to <tt>ActionBridge</tt>'s <tt>execute()</tt>.
+
* Line 10: Handling an events by passing an <code>Action</code> object implemented with your business logic to <code>ActionBridge</code>'s <code>execute()</code>.
* Line 11: Override <tt>Action</tt>'s <tt>execute()</tt> to implement clearing cell texts.
+
* Line 11: Override <code>Action</code>'s <code>execute()</code> to implement clearing cell texts.
  
Then <tt>ActionBridge</tt> will response corresponding update script to update the Spreadsheet in <tt>app4l.xhtml</tt>.
+
Then <code>ActionBridge</code> will response corresponding update script to update the Spreadsheet in <code>app4l.xhtml</code>.
  
== Check Cells ==
+
== doOK() ==
The same rule applies to "check cells" case, and we just list codes of <tt>Action</tt> for your reference.
+
The same rule applies to "doOK()" method, and we just list codes of <code>Action</code> for your reference.
  
<source lang='java' high='7,8'>
+
<source lang='java' highlight='7,8'>
  
 
@ManagedBean
 
@ManagedBean
Line 281: Line 282:
  
 
= Source Code of Example =
 
= Source Code of Example =
Source code of above example application can be accessed in [https://github.com/zkoss/zsscml/tree/master/zssjsfdemo github].
+
Source code of above example application can be accessed in [https://github.com/zkoss/zssjsfdemo github].
  
  

Latest revision as of 12:48, 19 January 2022


Using Spreadsheet JSF Component






Available in ZK Spreadsheet EE only

Overview

In this section, we will demonstrate how to make other JSF components interact with Spreadsheet in a JSF page using the AJAX tag. We assume that you know some basics about JSF including life cycle, tag usage, event handling, AJAX tag, and managed bean.

The example application is a simple page to request for leave. A user fills the required field in cells and click "OK" button to submit his request for leave. Or he can clicks "Reset" button to reset what he inputs to default value. The screenshot below shows a request of a user "John":

Essentials-jsp-app.png


Create a JSF Page

Spreadsheet can be embedded in a JSF page in the same way as JSF standard components. First specify ZK Spreadsheet component namespace URI http://www.zkoss.org/jsf/zss declaration along with other JSF namespace declarations and you can use the tag like <zssjsf:spreadsheet/>. If we want to interact with Spreadsheet in JSF AJAX tag, we should also put a <zssjsf:update/> component which is invisible in the browser in on the same page to process ZK AU response. Let's see the JSF page of our example application.

app4l.xhtml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:zssjsf="http://www.zkoss.org/jsf/zss"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:h="http://java.sun.com/jsf/html">
<h:head>
	<title>Application for Leave</title>
	<zssjsf:head/>
</h:head>
<h:body>
	<h:form id="form">
		<div>
			
			<zssjsf:spreadsheet id="myzss" 
				book="#{applicationForLeave.book}"
				actionBridge="#{applicationForLeave.actionBridge}" 
				width="800px" height="500px" 
				maxVisibleRows="50" maxVisibleColumns="20"
				showToolbar="true" showFormulabar="true"
				showContextMenu="true" showSheetbar="true"/>
			<h:panelGrid columns="3">
				<h:commandButton value="Reset"
					action="#{applicationForLeave.doReset}" >
					<f:ajax execute="@all" render="msg zkupdate"/>
				</h:commandButton>				
				<h:commandButton value="Ok"
					action="#{applicationForLeave.doOk}">
					<f:ajax execute="@all" render="msg zkupdate" />
				</h:commandButton>
				<h:messages id="msg"/>
			</h:panelGrid>
		</div>
		<zssjsf:update id="zkupdate"/>
	</h:form>
</h:body>
</html>
  • Line 16: ZK Spreadsheet JSF component tag supports all the properties that are supported by Spreadsheet ZUL component tag.
  • Line 17: The book attribute is used to bind a Book to spreadsheet from a managed bean.
  • Line 18: The actionBridge attribute is only available on Spreadsheet JSF component which is used to set an ActionBridge to a managed bean. This object will be explained in next section.
  • Line 25, 29: We use JSF's AJAX tag to trigger event handler methods defined in our managed bean. The component ID in execute attribute must include zssjsf:spreadsheet ID, and here we use @all just for convenience. The render attribute must include zssjsf:update ID.
  • Line 35: The update is another JSF component provided by ZK Spreadsheet which is responsible for processing ZK AU response.

Managed Bean

It's a standard practice to bind a JSF component with a managed bean which contains data model and business logic. Spreadsheet JSF component obtains Book object from attribute book and set ActionBridge to a managed bean's actionBridge

@ManagedBean
@RequestScoped
public class ApplicationForLeave {

	// the book of spreadsheet
	private Book book;
	
	 //the bridge to execute action in ZK context
	private ActionBridge actionBridge;
	private String dateFormat = "yyyy/MM/dd";

	public Book getBook() {
		if (book != null) {
			return book;
		}
		try {
			URL bookUrl = FacesContext.getCurrentInstance()
					.getExternalContext()
					.getResource("/WEB-INF/books/application_for_leave.xlsx");
			book = Importers.getImporter().imports(bookUrl, "app4leave");
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
		Locales.setThreadLocal(Locale.getDefault());
		
		Sheet sheet = book.getSheetAt(0);

		// reset sample data
		// you can use a cell reference to get a range
		Range from = Ranges.range(sheet, "E5");// Ranges.range(sheet,"From");
		// or you can use a name to get a range (the named range has to be set in book);
		Range to = Ranges.rangeByName(sheet, "To");
		Range reason = Ranges.rangeByName(sheet, "Reason");
		Range applicant = Ranges.rangeByName(sheet, "Applicant");
		Range requestDate = Ranges.rangeByName(sheet, "RequestDate");

		// use range api to set the cell data
		from.setCellEditText(DateUtil.tomorrow(0, dateFormat));
		to.setCellEditText(DateUtil.tomorrow(0, dateFormat));
		reason.setCellEditText("");
		applicant.setCellEditText("");
		requestDate.setCellEditText(DateUtil.today(dateFormat));

		return book;
	}

	public void setBook(Book book) {
		this.book = book;
	}
	
	public ActionBridge getActionBridge() {
		return actionBridge;
	}

	public void setActionBridge(ActionBridge actionBridge) {
		this.actionBridge = actionBridge;
	}
...
}
  • Line 12,20: Import a file for a Spreadsheet.
  • Line 56: The actionBridge will be set by Spreadsheet JSF component.

Implement Event Handler Method

In JSF, we can use the syntax below to invoke an event handler method, doReset(), of a managed bean ( applicationForLeave) in AJAX request.

<h:commandButton value="Reset" action="#{applicationForLeave.doReset}" >
	<f:ajax execute="@all" render="msg zkupdate" />
</h:commandButton>

Because of accessing ZK components like Spreadsheet needs to be in a ZK execution, we can use ActionBridge to help us. One new ActionBridge object is provided by Spreadsheet JSF component for each request to a managed bean via setter. All we have to do is to specify in actionBridge attribute with a managed bean's property like:

			<zssjsf:spreadsheet id="myzss"
				actionBridge="#{applicationForLeave.actionBridge}"  .../>

Then, we can use this ActionBridge to execute our business logic: reset and check cells.


Handling Spreadsheet Data Model

Inside ActionBridge.execute(), you can use those APIs we mentioned in Handling Data Model to implement your business logic. In our example, we use Range to set cell edit text and get value from cells.


doReset()

The usage of ActionBridge is to call its execute() with an Action object and we implement our business logic in Action's execute() method with those APIs mentioned in previous sections. In "reset cells" case, we use Range to clear cell text.

@ManagedBean
@RequestScoped
public class ApplicationForLeave {

...
public void doReset() {
		
		//use actionBridge to execute the action inside zk context
		//so the spreadsheet can get the update of book automatically
		actionBridge.execute(new Action() {
			public void execute() {
				Sheet sheet = book.getSheetAt(0);

				// reset sample data
				// you can use a cell reference to get a range
				Range from = Ranges.range(sheet, "E5");// Ranges.range(sheet,"From");
				// or you can use a name to get a range (the named range has to be
				// set in book);
				Range to = Ranges.rangeByName(sheet, "To");
				Range reason = Ranges.rangeByName(sheet, "Reason");
				Range applicant = Ranges.rangeByName(sheet, "Applicant");
				Range requestDate = Ranges.rangeByName(sheet, "RequestDate");

				// use range api to set the cell data
				from.setCellEditText(DateUtil.tomorrow(0, dateFormat));
				to.setCellEditText(DateUtil.tomorrow(0, dateFormat));
				reason.setCellEditText("");
				applicant.setCellEditText("");
				requestDate.setCellEditText(DateUtil.today(dateFormat));
			}
		});
		addMessage("Reset book");
	}

	private void addMessage(String message){
		FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(message));
	}
}
  • Line 10: Handling an events by passing an Action object implemented with your business logic to ActionBridge's execute().
  • Line 11: Override Action's execute() to implement clearing cell texts.

Then ActionBridge will response corresponding update script to update the Spreadsheet in app4l.xhtml.

doOK()

The same rule applies to "doOK()" method, and we just list codes of Action for your reference.

@ManagedBean
@RequestScoped
public class ApplicationForLeave {
...
	public void doOk() {
		//access cell data
		actionBridge.execute(new Action() {
			public void execute() {
				Sheet sheet = book.getSheetAt(0);

				Date from = Ranges.rangeByName(sheet,"From").getCellData().getDateValue();
				Date to = Ranges.rangeByName(sheet,"To").getCellData().getDateValue();
				String reason = Ranges.rangeByName(sheet,"Reason").getCellData().getStringValue();
				Double total = Ranges.rangeByName(sheet,"Total").getCellData().getDoubleValue();
				String applicant = Ranges.rangeByName(sheet,"Applicant").getCellData().getStringValue();
				Date requestDate = Ranges.rangeByName(sheet,"RequestDate").getCellData().getDateValue();
				
				//validate input
				if(from == null){
					addMessage("FROM is empty");
				}else if(to == null){
					addMessage("TO is empty");
				}else if(total==null || total.intValue()<0){
					addMessage("TOTAL small than 1");
				}else if(reason == null){
					addMessage("REASON is empty");
				}else if(applicant == null){
					addMessage("APPLICANT is empty");
				}else if(requestDate == null){
					addMessage("REQUEST DATE is empty");
				}else{
					//Handle your business logic here 
					
					addMessage("Your request are sent, following is your data");

					addMessage("From :" +from);
					addMessage("To :" + to);
					addMessage("Reason :"+ reason);
					addMessage("Total :"+ total.intValue());//we only need int
					addMessage("Applicant :"+ applicant);
					addMessage("RequestDate :"+ requestDate.getTime());
					
					//You can also store the book, and load it back later by exporting it to a file
					Exporter exporter = Exporters.getExporter();
					FileOutputStream fos = null;
					try {
						File temp = File.createTempFile("app4leave_", ".xlsx");
						fos = new FileOutputStream(temp); 
						exporter.export(sheet.getBook(), fos);
						System.out.println("file save at "+temp.getAbsolutePath());
						
						addMessage("Archive "+ temp.getName());
					} catch (IOException e) {
						e.printStackTrace();
					} finally{
						if(fos!=null)
							try {
								fos.close();
							} catch (IOException e) {
								//handle the exception
							}
					}
				}
			}
		});
	}
}

Source Code of Example

Source code of above example application can be accessed in github.



All source code listed in this book is at Github.


Last Update : 2022/01/19

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