ZK/How-Tos/Component Development

Component Development

edit

Grid

edit

How do develop an expanding grid with a pop-up window to add new rows to the grid

edit

First setup the page that has the grid that you want to expand:

<?page id="main-page"?>
<window title="Expanding Grid" border="normal" width="360px" id="food-to-go-delegate">
<zscript>
String[][] values = {
{"one", "1"}
,{"two","2"}
};
</zscript>
 <grid>
 <columns>
 <column label="Menu Item" sortAscending="${asc}" sortDescending="${dsc}"/>
 <column label="Price"/>
 </columns>
 <rows id="rows" use="org.zkforge.ftg.ExpandingMenuItemRows">
 <row forEach="${values}">
 <label value="${each[0]}"/>
 <hbox>$<textbox value="${each[1]}"/></hbox>
 </row>
 </rows>
 </grid>
 <button label="Add More">
 <attribute name="onClick"><![CDATA[
 Window win = (Window) Executions.createComponents(
 "menu-items-popup.zul", null, null);
 win.doModal();
 ]]></attribute>
 </button>
</window>

There is quite a lot going on there. First off there is a static array called "values". This is simply there to demonstrate that we can use a forEach="${values}" to output a list of rows. Realistically that data would have been pulled from a database. The next thing to notice is that the <rows> tag with the id "rows" has a "use" attribute that specifies that a subclass of org.zkoss.zul.Rows is used to implement that xul element. It is in this custom sub-class that we can add a custom method to insert a new row into the grid:

package org.zkforge.ftg;

import org.zkoss.zul.Hbox;
import org.zkoss.zul.Label;
import org.zkoss.zul.Row;
import org.zkoss.zul.Rows;
import org.zkoss.zul.Textbox;

public class ExpandingMenuItemRows extends Rows {
 /*
  * This is just an arbitrary custom method that we can call from a zscript.
  * In it we programmatically create all of the elements that appear in the other 
  * rows. The code below simply creates: 
  *  <row><label value=""/><hbox>$<textbox value=""/></hbox></row>
  * and sets the two value attributes whatever was passed into the method. 
  */
 public void addRow(String name, String price){
 Label label = new Label();
 label.setValue(name);
 Label dollar = new Label();
 dollar.setValue("$");
 Textbox textbox = new Textbox();
 textbox.setValue(price);
 Hbox hbox = new Hbox();
 hbox.appendChild(dollar);
 hbox.appendChild(textbox);
 Row row = new Row();
 row.appendChild(label);
 row.appendChild(hbox);
 this.appendChild(row);
 }
}

So if we can get a zscript function to call that method then a new row will be appended into the grid. This logic is in the pop-up window in the file menu-items-popup.zul:

<window id="win" title="Add Menu Item" border="normal" width="200px" closable="true">
<zscript>
doAdd(String name, String price){
 rows = Path.getComponent("//main-page/food-to-go-delegate/rows");
 rows.addRow(name, price);
}
</zscript>
 <vbox>Name:<textbox id="name" value=""/> Price:<textbox id="price" value=""/></vbox> 
 <button label="Add" onClick="doAdd(name.value,price.value);win.detach()"/> <button label="Cancel" onClick="win.detach()"/>
</window>

In that model dialogue window we have two textboxes one for the name and one for the price. If the user clicks 'Add' the button calls a zscript function doAdd passing the two textbox values. doAdd() then does an IDSpace lookup for the <rows> element in the main page. <rows> has an id "rows" within the IDSpace of the window with id "food-to-go-delegate" on the page "main-page" which we write out with the syntax "//page/window/id". Once we have a reference our custom sub-class element we just invoke our custom method 'addRow'.

Using Preference Attribute for Customization

edit

How to access the preference specific to a component

edit

If you want to develop a component that is configurable by zk.xml, then you have to

1) Define a preference name that a deployer can use to configure in WEB-INF/zk.xml. For example,

<!-- zk.xml -->
<preference>
	<name>org.zkoss.zul.Window.defaultActionOnShow</name>
	<value>moveDown</value>
</preference>

2) Access it with the getPreference method of the org.zkoss.zk.ui.util.Configuration class.

However, there is one Configuration instance per Web application, and a component can belong to any Web application if ZK libraries (e.g., zk.jar) are shared by several Web applications. Thus, you can access the preference only if a component is attached to a page. A good moment is when the component is rendered. For example,

//Window.java
//getOuterAttrs is called when redraw() is called
public String getOuterAttrs() {
	StringBuffer sb = new StringBuffer().append(super.getOuterAttrs());
	HTMLs.appendAttribute(sb, "z.aos",
		getDesktop().getWebApp().getConfiguration()
			.getPreference("org.zkoss.zul.Window.defaultActionOnShow"));
	return sb.toString();
}

If you want to provide a static method to set the default (overrides the preference):

public String getOuterAttrs() {
	StringBuffer sb = new StringBuffer().append(super.getOuterAttrs());
	String aos = getDefaultActionOnShow();
	if (aos == null)
		aos = getDesktop().getWebApp().getConfiguration()
			.getPreference("org.zkoss.zul.Window.defaultActionOnShow");
	HTMLs.appendAttribute(sb, "z.aos", aos);
	return sb.toString();
}
public static String getDefaultActionOnShow() {
	return _daos;
}