Difference between revisions of "Zscript, java, EL"
m (correct highlight (via JWB)) |
|||
Line 2: | Line 2: | ||
{{ZKDevelopersGuidePageHeader}} | {{ZKDevelopersGuidePageHeader}} | ||
==Overview== | ==Overview== | ||
− | By default, code in < | + | By default, code in <code>zscript</code> is Java language. Therefore, any code written in <code>zscript</code> can move to java file by slightly modification. In retrospect, any code written in java file can move to <code>zscript</code> by slightly modification. After all, they are all java. |
− | It is convenient to use < | + | It is convenient to use <code>zscript</code> 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 <code>zscript</code> 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 < | + | 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 <code>zscript</code> if possible. Also, you '''CAN NOT''' use Java debug tool to debug <code>zscript</code>, you can't set breakpoints in zscript. Not like Java, sometimes obvious bug like typo can't be easily found in <code>zscript</code>. ZK has implemented <code>GenericAutowireComposer</code>, it eases the burden of moving code from <code>zscript</code> to java a lot. Please refer to the smalltalk [http://books.zkoss.org/wiki/Small%20Talks/2008/August/ZK%20MVC%20Made%20Easy] for detail. |
− | < | + | <code>zscript</code> is useful for prototyping, but it's more hard to debug and maintain. In the following paragraph, we'll show examples of equivalent <code>zscript</code> and java code. |
− | ==Use < | + | ==Use <code>zscript</code> to initialize== |
− | In Page Initial Phase, ZK processes the processing instructions, called < | + | In Page Initial Phase, ZK processes the processing instructions, called <code>init</code>. |
− | Use < | + | Use <code>zscript</code> 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: | For example: | ||
Line 22: | Line 22: | ||
Notice that the page is not yet attached to the desktop when the Page Initial phase executes. | 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 < | + | Use java to init the page, simply specify a class with class attribute, an instance of the specified class is constructed, and then its <code>doInit</code> method is called. |
For example: | For example: | ||
Line 30: | Line 30: | ||
==access UI component by ID== | ==access UI component by ID== | ||
− | < | + | <code>zscript</code> can access UI component by ID, in the following example, |
<source lang="xml" > | <source lang="xml" > | ||
<window id="win_1"> | <window id="win_1"> | ||
Line 45: | Line 45: | ||
</source> | </source> | ||
− | To access ui component in java code, you can use < | + | To access ui component in java code, you can use <code>Path.getComponent()</code> to obtain the mapping java object. |
<source lang="java" > | <source lang="java" > | ||
Line 52: | Line 52: | ||
</source> | </source> | ||
− | ==define Variable in < | + | ==define Variable in <code>zscript</code> and access by EL== |
− | Variable defined in < | + | Variable defined in <code>zscript</code> can be easily accessed by EL. |
<source lang="xml" > | <source lang="xml" > | ||
<window> | <window> | ||
Line 64: | Line 64: | ||
</source> | </source> | ||
− | The result shows < | + | The result shows <code>1:abc</code> |
To achieve the same result in java, you can rewrite it to | To achieve the same result in java, you can rewrite it to | ||
Line 86: | Line 86: | ||
</source> | </source> | ||
− | Note that < | + | Note that <code>${win_1.var}</code> 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 <code>get</code> in front of it. |
==Define class and methods in zscript== | ==Define class and methods in zscript== | ||
Line 99: | Line 99: | ||
</source> | </source> | ||
− | And you can define methods in < | + | And you can define methods in <code>zscript</code> |
<source lang="xml" > | <source lang="xml" > | ||
<window> | <window> | ||
Line 113: | Line 113: | ||
==access implicit object== | ==access implicit object== | ||
− | In < | + | In <code>zscript</code>, you can access implicit object like they are declared global variable. |
<source lang="xml" > | <source lang="xml" > | ||
Line 123: | Line 123: | ||
</source> | </source> | ||
− | the result shows < | + | the result shows <code>window</code>'s title becomes <code>given by zscript</code> |
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. | 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. | ||
Line 132: | Line 132: | ||
</source> | </source> | ||
− | < | + | <code>Desktop.java</code> has api such as <code>getExecution</code>, <code>getPage</code>, <code>getSession</code>, <code>getWebApp</code>. And <code>AbstractComponent.java</code> has <code>getSpaceOwner</code>, <code>getDesktop</code>. And <code>Execution</code> has <code>getArg</code>. And <code>ForEachImpl.java</code> has <code>getEach</code> |
− | For example, you can get the implicit object < | + | For example, you can get the implicit object <code>execution</code> from any component |
<source lang="java" > | <source lang="java" > | ||
comp.getDesktop().getExecution() | comp.getDesktop().getExecution() | ||
Line 140: | Line 140: | ||
== getVariable VS. getZScriptVariable == | == getVariable VS. getZScriptVariable == | ||
− | Variables defined in the namespace can be retrieved by use of the < | + | Variables defined in the namespace can be retrieved by use of the <code>getVariable</code> method. |
− | On the other hand, variables defined in < | + | On the other hand, variables defined in <code>zscript</code> 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 <code>getVariable</code> method. |
<source lang="xml" > | <source lang="xml" > | ||
Line 151: | Line 151: | ||
</source> | </source> | ||
− | Instead, you have to use < | + | Instead, you have to use <code>getZScriptVariable</code> to retrieve variables defined in <code>zscript</code>. Similarly, you can use <code>getZScriptClass</code> to retrieve classes and <code>getZScriptFunction</code> to retrieve methods defined in <code>zscript</code>. 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 < | + | If you want to search a particular interpreter, you can use the <code>getInterpreter</code> method to retrieve the interpreter first, as follows. |
<source lang="java" > | <source lang="java" > | ||
Line 180: | Line 180: | ||
==foreach== | ==foreach== | ||
− | It's a common usage of < | + | It's a common usage of <code>zscript</code> to define array of object for <code>forEach</code> |
<source lang="xml" > | <source lang="xml" > | ||
Line 194: | Line 194: | ||
</source> | </source> | ||
− | You can move the definition of array of object to java file as the following example. But remember to add < | + | You can move the definition of array of object to java file as the following example. But remember to add <code>id</code> inside <code>${}</code>, then EL knows which component has the variable. |
<source lang="xml" > | <source lang="xml" > | ||
Line 215: | Line 215: | ||
</source> | </source> | ||
− | Or you can use < | + | Or you can use <code>appendChild</code>. Manually generate all children in java, then you don't have to mix with <code>forEach</code> in ZUML. In the following example, the <code>listitem</code>s will be appended to <code>listbox</code> after the <code>button</code> is clicked. |
<source lang="xml" > | <source lang="xml" > | ||
<window id="win_1" use="MyWindow" title="list"> | <window id="win_1" use="MyWindow" title="list"> | ||
Line 244: | Line 244: | ||
==Macro Component== | ==Macro Component== | ||
− | ZK provides two way to provide additional methods to macro component. One is through java, and the other is through < | + | ZK provides two way to provide additional methods to macro component. One is through java, and the other is through <code>zscript</code>. Please refer to section '''Provide Additional Methods''' in chapter [[Macro_Components|Macro]] for more information. |
==event handler== | ==event handler== | ||
− | You can write event handler code in < | + | You can write event handler code in <code>zscript</code> or <code>forward</code> to event handler in java. |
− | If the code is really simple, you can write it in < | + | If the code is really simple, you can write it in <code>zscript</code> following event's name. Like following example: |
<source lang="xml" > | <source lang="xml" > | ||
<window> | <window> | ||
Line 256: | Line 256: | ||
</source> | </source> | ||
− | If the code is more than one line, for readability, you can use < | + | If the code is more than one line, for readability, you can use <code>attribute</code>. |
<source lang="xml" > | <source lang="xml" > | ||
<window> | <window> | ||
Line 267: | Line 267: | ||
</source> | </source> | ||
− | Or you can deliberately define a method in < | + | Or you can deliberately define a method in <code>zscript</code>, and call it from event's following <code>zscript</code>. |
<source lang="xml" > | <source lang="xml" > | ||
<window> | <window> | ||
Line 280: | Line 280: | ||
</source> | </source> | ||
− | To handle events in java, you define static java method, or use zk attributes: < | + | To handle events in java, you define static java method, or use zk attributes: <code>use</code> or <code>apply</code>. |
The following example shows how to call static method in java, | The following example shows how to call static method in java, | ||
Line 305: | Line 305: | ||
</source> | </source> | ||
− | The following example uses zk attribute: < | + | The following example uses zk attribute: <code>use</code> , |
<source lang="xml" > | <source lang="xml" > | ||
<window id="win_1" use="MyWindow"> | <window id="win_1" use="MyWindow"> | ||
Line 327: | Line 327: | ||
</source> | </source> | ||
− | The following example uses zk attribute: < | + | The following example uses zk attribute: <code>apply</code>. Note that name of event handling method must be <code>onXXX</code>. |
<source lang="xml" > | <source lang="xml" > | ||
Line 352: | Line 352: | ||
==GenericAutowireComposer== | ==GenericAutowireComposer== | ||
− | If you want to access UI object, you have to call < | + | If you want to access UI object, you have to call <code>getFellow</code> 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 <code>getFellow</code> calls, if your applied class extends <code>GenericAutowireComposer</code>. |
In the following example, Full Name is updated automatically while you change First Name or Last Name. | In the following example, Full Name is updated automatically while you change First Name or Last Name. |
Latest revision as of 13:25, 19 January 2022
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 listitem
s 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.