Difference between revisions of "Zscript, java, EL"
Line 6: | Line 6: | ||
It is convenient to use <tt>zscript</tt> in ZUML. The advantage is that no compilation is required and you can modify its content dynamically (without re-deploying the Web application). And the syntax is more intuitive, EL can access variables in <tt>zscript</tt> easily. | It is convenient to use <tt>zscript</tt> in ZUML. The advantage is that no compilation is required and you can modify its content dynamically (without re-deploying the Web application). And the syntax is more intuitive, EL can access variables in <tt>zscript</tt> easily. | ||
− | But it comes with a price: slower performance. The degradation varies from one application from another. For large website, it is suggested not to use <tt>zscript</tt> if possible. Also, you '''CAN NOT''' use Java debug tool to debug <tt>zscript</tt>, you can't set breakpoints in zscript. Not like Java, sometimes obvious bug like typo can't be easily found in <tt>zscript</tt>. ZK has implemented <tt>GenericAutowireComposer</tt>, it eases the burden of moving code from <tt>zscript</tt> to java a lot. Please refer to the smalltalk [http:// | + | But it comes with a price: slower performance. The degradation varies from one application from another. For large website, it is suggested not to use <tt>zscript</tt> if possible. Also, you '''CAN NOT''' use Java debug tool to debug <tt>zscript</tt>, you can't set breakpoints in zscript. Not like Java, sometimes obvious bug like typo can't be easily found in <tt>zscript</tt>. ZK has implemented <tt>GenericAutowireComposer</tt>, it eases the burden of moving code from <tt>zscript</tt> to java a lot. Please refer to the smalltalk [http://books.zkoss.org/wiki/Small%20Talks/2008/August/ZK%20MVC%20Made%20Easy] for detail. |
<tt>zscript</tt> is useful for prototyping, but it's more hard to debug and maintain. In the following paragraph, we'll show examples of equivalent <tt>zscript</tt> and java code. | <tt>zscript</tt> is useful for prototyping, but it's more hard to debug and maintain. In the following paragraph, we'll show examples of equivalent <tt>zscript</tt> and java code. | ||
− | |||
− | |||
− | |||
− | |||
==Use <tt>zscript</tt> to initialize== | ==Use <tt>zscript</tt> to initialize== |
Revision as of 02:25, 6 September 2016
This documentation is for an older version of ZK. For the latest one, please click here.
Overview
By default, code in zscript is Java language. Therefore, any code written in zscript can move to java file by slightly modification. In retrospect, any code written in java file can move to zscript by slightly modification. After all, they are all java.
It is convenient to use zscript in ZUML. The advantage is that no compilation is required and you can modify its content dynamically (without re-deploying the Web application). And the syntax is more intuitive, EL can access variables in zscript easily.
But it comes with a price: slower performance. The degradation varies from one application from another. For large website, it is suggested not to use zscript if possible. Also, you CAN NOT use Java debug tool to debug zscript, you can't set breakpoints in zscript. Not like Java, sometimes obvious bug like typo can't be easily found in zscript. ZK has implemented GenericAutowireComposer, it eases the burden of moving code from zscript to java a lot. Please refer to the smalltalk [1] for detail.
zscript is useful for prototyping, but it's more hard to debug and maintain. In the following paragraph, we'll show examples of equivalent zscript and java code.
Use zscript to initialize
In Page Initial Phase, ZK processes the processing instructions, called init.
Use zscript to init the page,simply specify a file containing the scripting codes with the zscript attribute, as follows. Then, the file will be interpreted at the Page Initial phase.
For example:
<?init zscript="/my/init.zs"?>
Notice that the page is not yet attached to the desktop when the Page Initial phase executes.
Use java to init the page, simply specify a class with class attribute, an instance of the specified class is constructed, and then its doInit method is called.
For example:
<?init class="MyInit"?>
access UI component by ID
zscript can access UI component by ID, in the following example,
<window id="win_1">
<zscript><![CDATA[
win_1.title="given by zscript";
]]>
</zscript>
</window>
the result will be:
given by zscript
To access ui component in java code, you can use Path.getComponent() to obtain the mapping java object.
Window win = (Window)Path.getComponent("/win_1");
win.setTitle("given by java");
define Variable in zscript and access by EL
Variable defined in zscript can be easily accessed by EL.
<window>
<zscript><![CDATA[
var="abc";
]]>
</zscript>
1:${var}
</window>
The result shows 1:abc
To achieve the same result in java, you can rewrite it to
<window id="win_1" use="MyWindow">
1:${win_1.var}
</window>
And the java file:
import org.zkoss.zul.Window;
public class MyWindow extends Window {
String var = "abc";
public String getVar(){
return var;
}
}
Note that ${win_1.var} will be mapped to MyWindow.getVar(). It's case sensitive. The mapping getter function will map first character of variable to upper case and append get in front of it.
Define class and methods in zscript
Thanks to the power of BeanShell, the implementation of Java classes can be done in zscript as follows.
<zscript>
public class MyWindow extends Window {
}
</zscript>
<window use="MyWindow"/>
And you can define methods in zscript
<window>
<zscript><![CDATA[
public void sayHello(){
alert("hello");
}
]]>
</zscript>
<button label="Say Hello!" onClick="sayHello()" />
</window>
access implicit object
In zscript, you can access implicit object like they are declared global variable.
<window>
<zscript>
self.title="given by zscript";
</zscript>
</window>
the result shows window's title becomes given by zscript
Not every implicit object has its own mapping java object. But there is always a workaround. If you want to access attribute in desktopScope, the following two statements are equivalent, assuming comp is a component.
comp.getAttribute("some", comp.DESKTOP_SCOPE);
comp.getDesktop().getAttribute("some");
Desktop.java has api such as getExecution, getPage, getSession, getWebApp. And AbstractComponent.java has getSpaceOwner, getDesktop. And Execution has getArg. And ForEachImpl.java has getEach
For example, you can get the implicit object execution from any component
comp.getDesktop().getExecution()
getVariable VS. getZScriptVariable
Variables defined in the namespace can be retrieved by use of the getVariable method.
On the other hand, variables defined in zscript is part of the interpret that interprets it. They are not a part of any namespace. In other words, you can not retrieve them by use of the getVariable method.
<zscript>
var1 = 123; //var1 belongs to the interpreter, not any namespace
page.getVariable("var1"); //returns null
</zscript>
Instead, you have to use getZScriptVariable to retrieve variables defined in zscript. Similarly, you can use getZScriptClass to retrieve classes and getZScriptFunction to retrieve methods defined in zscript. These methods will iterate through all loaded interpreters until the specified one is found.
If you want to search a particular interpreter, you can use the getInterpreter method to retrieve the interpreter first, as follows.
page.getInterpreter("JavaScript").getVariable("some"); //interpreter for JavaScript
page.getInterpreter(null).getVariable("some"); //interpreter for default language
The Scripting Codes in a Separate File
To separate codes and views, developers could put the scripting codes in a separated file, say sayHello.zs, and then use the src attribute to reference it.
<window>
<button label="Say Hello" onClick="sayHello()"/>
<zscript src="sayHello.zs"/>
</window>
which assumes the content of sayHello.zs is as follows.
int count = 0;
void sayHello() { //declare a global function
alert("Hello World! "+ ++count);
}
foreach
It's a common usage of zscript to define array of object for forEach
<window>
<zscript><![CDATA[
contacts = new String[] {"Monday", "Tuesday", "Wednesday"};
]]>
</zscript>
<listbox>
<listitem label="${each}" forEach="${contacts}"/>
</listbox>
</window>
You can move the definition of array of object to java file as the following example. But remember to add id inside ${}, then EL knows which component has the variable.
<window id="win_1" use="MyWindow">
<listbox>
<listitem label="${each}" forEach="${win_1.contacts}"/>
</listbox>
</window>
import org.zkoss.zul.Window;
public class MyWindow extends Window {
String[] contacts = new String[] {"Monday", "Tuesday", "Wednesday"};
public String[] getContacts(){
return contacts;
}
}
Or you can use appendChild. Manually generate all children in java, then you don't have to mix with forEach in ZUML. In the following example, the listitems will be appended to listbox after the button is clicked.
<window id="win_1" use="MyWindow" title="list">
<listbox id="lb_1">
</listbox>
<button label="Hello" onClick="win_1.onTest()"/>
</window>
import org.zkoss.zul.Listbox;
import org.zkoss.zul.Listitem;
import org.zkoss.zul.Window;
public class MyWindow extends Window {
String[] contacts = new String[] { "Monday", "Tuesday", "Wednesday" };
public void onTest() {
Listbox lb = (Listbox) getFellow("lb_1");
for (int i = 0; i < contacts.length; i++) {
Listitem li = new Listitem();
li.setLabel(contacts[i]);
lb.appendChild(li);
}
}
}
Macro Component
ZK provides two way to provide additional methods to macro component. One is through java, and the other is through zscript. Please refer to section Provide Additional Methods in chapter Macro for more information.
event handler
You can write event handler code in zscript or forward to event handler in java.
If the code is really simple, you can write it in zscript following event's name. Like following example:
<window>
<button onClick='alert("here is a zcript")'/>
</window>
If the code is more than one line, for readability, you can use attribute.
<window>
<button>
<attribute name="onClick">
alert("here is a zscript");
</attribute>
</button>
</window>
Or you can deliberately define a method in zscript, and call it from event's following zscript.
<window>
<zscript><![CDATA[
public void showAlert(){
alert("here is a zcript too");
}
]]>
</zscript>
<button onClick="showAlert()"/>
</window>
To handle events in java, you define static java method, or use zk attributes: use or apply.
The following example shows how to call static method in java,
<window>
<button onClick="MyManager.showAlert()"/>
</window>
And MyManager.java
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Window;
public class MyManager {
public static void showAlert(){
try {
Messagebox.show("handle event in java");
} catch (Exception e) {
e.printStackTrace();
}
}
}
The following example uses zk attribute: use ,
<window id="win_1" use="MyWindow">
<button onClick="win_1.showAlert()"/>
</window>
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Window;
public class MyWindow extends Window {
public void showAlert(){
try {
Messagebox.show("handle event in java");
} catch (Exception e) {
e.printStackTrace();
}
}
}
The following example uses zk attribute: apply. Note that name of event handling method must be onXXX.
<window apply="MyComposer">
<button forward="onShowAlert()"/>
</window>
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.util.GenericComposer;
import org.zkoss.zul.Messagebox;
public class MyComposer extends GenericComposer {
public void onShowAlert(Event evt) {
try {
Messagebox.show("handle event in java");
} catch (Exception e) {
e.printStackTrace();
}
}
}
GenericAutowireComposer
If you want to access UI object, you have to call getFellow to get its mapping java object. But why not just bind these components and data beans automatically? In the following example, you can omit the tedious getFellow calls, if your applied class extends GenericAutowireComposer.
In the following example, Full Name is updated automatically while you change First Name or Last Name.
<window apply="Autowired">
<grid>
<rows>
<row>First Name: <textbox id="firstName" forward="onChange=onFirstName"/></row>
<row>Last Name: <textbox id="lastName" forward="onChange=onLastName"/></row>
<row>Full Name: <label id="fullName"/></row>
</rows>
</grid>
</window>
And the source code of Autowired.java:
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.util.GenericAutowireComposer;
import org.zkoss.zul.Label;
import org.zkoss.zul.Textbox;
public class Autowired extends GenericAutowireComposer {
private Textbox firstName; //auto-wired
private Textbox lastName; //auto-wired
private Label fullName; //auto-wired
//all getFellow() codes are removed
public void onFirstName(Event event) {
fullName.setValue(firstName.getValue()+" "+lastName.getValue());
}
public void onLastName(Event event) {
fullName.setValue(firstName.getValue()+" "+lastName.getValue());
}
}
For detail information, please refer to ZK MVC Made Easy.