EL Expressions"

From Documentation
m (remove empty version history (via JWB))
 
(51 intermediate revisions by 7 users not shown)
Line 1: Line 1:
 
{{ZKDevelopersReferencePageHeader}}
 
{{ZKDevelopersReferencePageHeader}}
 +
=Overview=
 +
EL expressions are designed to make a ZUML document easier to access objects available in the application, such as the application data and parameters. For a complete introduction, please refer to [[ZUML Reference/EL Expressions]].
  
=Overview=
+
An EL expression is an expression enclosed with <code>${</code> and <code>}</code>, i.e., the syntax <code>${expr}</code>. For example,
An EL expressions is an expression enclosed with <tt>${</tt> and <tt>}</tt>, i.e., the syntax is <tt>${expr}</tt>. For example,
 
  
 
<source lang="xml" >
 
<source lang="xml" >
Line 10: Line 11:
 
</source>
 
</source>
 
   
 
   
When an EL expression is used as an attribute value, it could return any kind of objects as long as the attribute allows. For example, the following expressions will be evaluated to <tt>boolean</tt> and <tt>int</tt>, respectively.
+
When an EL expression is used as an attribute value, it could return any kind of objects as long as the attribute allows. For example, the following expressions will be evaluated to <code>boolean</code> and <code>int</code> respectively.
  
 
<source lang="xml" >
 
<source lang="xml" >
Line 17: Line 18:
 
</source>
 
</source>
  
If the class does not match, ZK Loader will try to coerce it to the correct one. If failed, an exception is thrown.
+
If the class does not match, ZK Loader will try to coerce it to the correct one. If a failure has occurred, an exception is thrown.
  
 
Multiple EL expressions could be specified in a single attribute:
 
Multiple EL expressions could be specified in a single attribute:
Line 25: Line 26:
 
</source>
 
</source>
  
=Example=
+
==Example==
  
{| border='1px'
+
{| class='wikitable' | width="100%"
 
! EL Expression !! Result
 
! EL Expression !! Result
 
|-
 
|-
Line 48: Line 49:
 
| 0.75
 
| 0.75
 
|-
 
|-
| ${10 div 4}
+
| ${10 mod 4}
 
| 2
 
| 2
 
|-
 
|-
 
| ${empty param.add}
 
| ${empty param.add}
| true if the request parameter named <tt>add</tt> is null or an empty string  
+
| true if the request parameter named <code>add</code> is null or an empty string  
 
|-
 
|-
 
| ${param['mycom.productId']}
 
| ${param['mycom.productId']}
| The value of the request parameter named <tt>mycom.productId</tt>
+
| The value of the request parameter named <code>mycom.productId</code>
 
|}
 
|}
 
* The example is from [http://download.oracle.com/javaee/1.4/tutorial/doc/JSPIntro7.html JSP Tutorial].
 
* The example is from [http://download.oracle.com/javaee/1.4/tutorial/doc/JSPIntro7.html JSP Tutorial].
 +
* For more information please refer to [[ZUML Reference/EL Expressions/Operators|Operators]] and [[ZUML Reference/EL Expressions/Literals|Literals]].
  
 
==Difference from Java==
 
==Difference from Java==
  
* A string can be enclosed with single quote or double double. In other words, 'abc' and "abc" are the same.
+
* A string can be enclosed with either single quotes or double quotes. In other words, 'abc' is equivalent to "abc".
* The empty operator is useful for testing null and empty (string, list and map), such as ${empty param.add}.
+
* The empty operator is useful for testing null and empty string, list and map, such as ${empty param.add}.
* The . operator can be used to access a property of an object (assuming there is a get method of the same name), or a value of a map.
+
* The . operator can be used to access a property of an object (assuming that there is a get method of the same name) or a value of a map, such as ${foo.value.name}.
* The [] operator can be used to access an item of a list or array, a value of a map, and a property of an object (assuming there is a get method of the same name), such as ${wnd['title']}.
+
* The [ ] operator can be used to access an item of a list or array, a value of a map, and a property of an object (assuming that there is a get method of the same name), such as ${ary[5]} and ${wnd['title']}.
 +
* <code>null</code> is returned if the value is not found and the index is out-of-bound.
  
 
For more information please refer to [[ZUML Reference/EL Expressions/Operators|Operators]] and [[ZUML Reference/EL Expressions/Literals|Literals]].
 
For more information please refer to [[ZUML Reference/EL Expressions/Operators|Operators]] and [[ZUML Reference/EL Expressions/Literals|Literals]].
  
=Version History=
+
 
{{LastUpdated}}
+
 
{| border='1px' | width="100%"
+
= Resolving EL Variables =
! Version !! Date !! Content
+
EL expressions are evaluated on the server when the page is rendered. Thus, an EL variable can access:
|-
+
 
| &nbsp;
+
* Components by [[ZK Developer's Reference/UI Composing/Component-based UI|using its ID]]
| &nbsp;
+
* Variables defined in [[ZK Developer's Reference/UI Composing/ZUML/Scripts in ZUML|zscript]]
| &nbsp;
+
* [[ZUML Reference/EL Expressions/Implicit Objects|Implicit objects]]
|}
+
* Scoped attributes
 +
 
 +
<source lang="xml">
 +
<!-- self is an implicit object referring to the component itself -->
 +
<textbox id="tb" value="${self.parent.title}"/>
 +
 
 +
<!-- tb, the ID of a textbox, is the object reference of the textbox component -->
 +
${tb.value}
 +
 
 +
<!-- param is an implicit object  -->
 +
<button label="Enter" if="${not empty param.edit}"/>
 +
 
 +
<zscript><![CDATA[
 +
    Date now = new Date();
 +
]]></zscript>
 +
<!-- now is a variable defined in zscript -->
 +
<datebox value="${now}"/>
 +
</source>
 +
 
 +
== Resolving Order ==
 +
ZK resolves a variable from smaller scope to larger scope in the order below:
 +
 
 +
# zscript variable
 +
# execution
 +
# component
 +
# page
 +
# desktop
 +
# session
 +
# application
 +
 
 +
Hence, if there is an attribute value in a smaller scope, it will shadow the same attribute in the larger scope.
 +
 
 +
<syntaxhighlight line lang='xml'>
 +
<div id="parent">
 +
    <zscript><![CDATA[
 +
    //the smaller scope (lower one) can shadow the upper one
 +
    application.setAttribute("myname", "in application");
 +
    session.setAttribute("myname", "in session");
 +
    desktop.setAttribute("myname", "in desktop");
 +
    page.setAttribute("myname", "in page");
 +
    parent.setAttribute("myname", "in component");
 +
    execution.setAttribute("myname", "in execution");
 +
    ]]></zscript>
 +
    Resolved result:
 +
    <label style="font-weight: bold" value="${myname}"/>
 +
</div>
 +
</syntaxhighlight>
 +
In the example above, the resolved result is '''in execution'''. But if you remove line 9, you will see '''in component'''.
 +
 
 +
(check org.zkoss.zk.xel.impl.ExecutionResolver.resolveVariable0())
 +
 
 +
Furthermore, you could define a variable resolver to associate a name with an object or map a function to a Java static method as described in the following.
 +
 
 +
==Variable Resolver==
 +
 
 +
If you would like to support many variables, you could implement a variable resolver: a class that implements <javadoc type="interface">org.zkoss.xel.VariableResolver</javadoc>.
 +
 
 +
<source lang="java">
 +
package foo;
 +
public class CustomerResolver implements org.zkoss.xel.VariableResolver {
 +
    public Object resolveVariable(String name) {
 +
        if ("customers".equals(name))
 +
            return Customer.getAll("*");
 +
//    if ("recent".equals(name))
 +
//        return something_else;
 +
        return null; //not a recognized variable
 +
    }
 +
}
 +
</source>
 +
 
 +
Then, you could specify it in a [[ZUML Reference/ZUML/Processing Instructions/variable-resolver|variable-resolver]] directive, such as:
 +
 
 +
<source lang="xml">
 +
<?variable-resolver class="foo.CustomerResolve"?>
 +
 
 +
<listbox>
 +
    <listitem label="${each.name}" forEach="${customers}"/>
 +
</listbox>
 +
</source>
 +
 
 +
===System-level Variable Resolver===
 +
 
 +
If you have a variable resolver that will be used on every page, you can register a system-level variable resolver rather than specifying it on every page.
 +
 
 +
This can be done by specifying a variable resolver you have implemented in <code>WEB-INF/zk.xml</code> as follows. For more information, please refer to [[ZK Configuration Reference/zk.xml/The listener Element|ZK Configuration Reference]].
 +
 
 +
<source lang="xml">
 +
<listener>
 +
    <listener-class>foo.MyVariableResolver</listener-class>
 +
</listener>
 +
</source>
 +
 
 +
Then, when a page is created each time, an instance of the specified class will be instantiated and registered as if it is specified in [[ZUML Reference/ZUML/Processing Instructions/variable-resolver|the variable-resolver element]].
 +
 
 +
Notice that since a new instance of the variable resolver is created on each page, there will not be any concurrency issues.
 +
 
 +
=Calling Java Methods=
 +
 
 +
 
 +
==Define in Page-Scope==
 +
 
 +
The collection object could be retrieved by invoking a static method. For example, suppose that we have a class and a static method as follows:
 +
 
 +
<source lang="java">
 +
package foo;
 +
public class Customer {
 +
    public static Collection<Customer> getAll(String condition) {
 +
        //...returns a collection of customers
 +
    }
 +
    public String getName() {
 +
      return _name;
 +
    }
 +
    //...
 +
}
 +
</source>
 +
 
 +
Then, we could retrieve them with the [[ZUML Reference/ZUML/Processing Instructions/xel-method|xel-method]] directive:
 +
 
 +
<source lang="xml">
 +
<?xel-method prefix="c" name="getAllCustomers" class="foo.Customer"
 +
  signature="java.util.Collection getAll(java.lang.String)"?><!-- Generics not allowed -->
 +
<listbox>
 +
    <listitem label="${each.name}" forEach="${c:getAllCustomers('*')}"/>
 +
</listbox>
 +
</source>
 +
 
 +
==Define as a Tag Library==
 +
If you have several static methods, you can declare them in an XML file called taglib, such as
 +
 
 +
<source lang="xml">
 +
<taglib>
 +
<function>
 +
<name>getAllCustomers</name>
 +
<function-class>foo.Customer</function-class>
 +
<function-signature>
 +
java.util.Collection getAll(java.lang.String)
 +
</function-signature>
 +
<description>
 +
Returns a collection of customers.
 +
</description>
 +
</function>
 +
<!-- any number of functions are allowed -->
 +
</taglib>
 +
</source>
 +
 
 +
Then, you can use them by specifying it in a [[ZUML Reference/ZUML/Processing Instructions/taglib|taglib directive]].
 +
 
 +
<source lang="xml">
 +
<?taglib uri="/WEB-INF/tld/my.tld" prefix="my"?>
 +
<listbox>
 +
    <listitem label="${each.name}" forEach="${my:getAllCustomers('*')}"/>
 +
</listbox>
 +
</source>
 +
 
 +
= EL 3.0 Support=
 +
Since ZK 8, ZK supports some syntaxes of Java EE 7 Expression Language 3, see [http://books.zkoss.org/zk-mvvm-book/9.5/data_binding/el_expression.html examples].
 +
 
 +
 
 +
 
  
 
{{ZKDevelopersReferencePageFooter}}
 
{{ZKDevelopersReferencePageFooter}}

Latest revision as of 05:54, 6 February 2024

Overview

EL expressions are designed to make a ZUML document easier to access objects available in the application, such as the application data and parameters. For a complete introduction, please refer to ZUML Reference/EL Expressions.

An EL expression is an expression enclosed with ${ and }, i.e., the syntax ${expr}. For example,

 <element attr1="${bean.property}".../>
 ${map[entry]}
 <another-element>${3+counter} is ${empty map}</another-element>

When an EL expression is used as an attribute value, it could return any kind of objects as long as the attribute allows. For example, the following expressions will be evaluated to boolean and int respectively.

 <window if="${some > 10}"><!-- boolean -->
   <progressmetter value="${progress}"/><!-- integer -->

If the class does not match, ZK Loader will try to coerce it to the correct one. If a failure has occurred, an exception is thrown.

Multiple EL expressions could be specified in a single attribute:

<window title="${foo.name}: ${foo.version}">

Example

EL Expression Result
${1 > (4/2)} false
${100.0 == 100} true
${'a' < 'b'} true
${'hip' gt 'hit'} false
${1.2E4 + 1.4} 12001.4
${3 div 4} 0.75
${10 mod 4} 2
${empty param.add} true if the request parameter named add is null or an empty string
${param['mycom.productId']} The value of the request parameter named mycom.productId

Difference from Java

  • A string can be enclosed with either single quotes or double quotes. In other words, 'abc' is equivalent to "abc".
  • The empty operator is useful for testing null and empty string, list and map, such as ${empty param.add}.
  • The . operator can be used to access a property of an object (assuming that there is a get method of the same name) or a value of a map, such as ${foo.value.name}.
  • The [ ] operator can be used to access an item of a list or array, a value of a map, and a property of an object (assuming that there is a get method of the same name), such as ${ary[5]} and ${wnd['title']}.
  • null is returned if the value is not found and the index is out-of-bound.

For more information please refer to Operators and Literals.


Resolving EL Variables

EL expressions are evaluated on the server when the page is rendered. Thus, an EL variable can access:

<!-- self is an implicit object referring to the component itself -->
<textbox id="tb" value="${self.parent.title}"/>

<!-- tb, the ID of a textbox, is the object reference of the textbox component -->
${tb.value}

<!-- param is an implicit object   -->
<button label="Enter" if="${not empty param.edit}"/>

<zscript><![CDATA[
     Date now = new Date();
]]></zscript>
<!-- now is a variable defined in zscript -->
<datebox value="${now}"/>

Resolving Order

ZK resolves a variable from smaller scope to larger scope in the order below:

  1. zscript variable
  2. execution
  3. component
  4. page
  5. desktop
  6. session
  7. application

Hence, if there is an attribute value in a smaller scope, it will shadow the same attribute in the larger scope.

 1 <div id="parent">
 2     <zscript><![CDATA[
 3     //the smaller scope (lower one) can shadow the upper one
 4     application.setAttribute("myname", "in application");
 5     session.setAttribute("myname", "in session");
 6     desktop.setAttribute("myname", "in desktop");
 7     page.setAttribute("myname", "in page");
 8     parent.setAttribute("myname", "in component");
 9     execution.setAttribute("myname", "in execution");
10     ]]></zscript>
11     Resolved result:
12     <label style="font-weight: bold" value="${myname}"/>
13 </div>

In the example above, the resolved result is in execution. But if you remove line 9, you will see in component.

(check org.zkoss.zk.xel.impl.ExecutionResolver.resolveVariable0())

Furthermore, you could define a variable resolver to associate a name with an object or map a function to a Java static method as described in the following.

Variable Resolver

If you would like to support many variables, you could implement a variable resolver: a class that implements VariableResolver.

package foo;
public class CustomerResolver implements org.zkoss.xel.VariableResolver {
    public Object resolveVariable(String name) {
        if ("customers".equals(name))
            return Customer.getAll("*");
//     if ("recent".equals(name))
//         return something_else;
        return null; //not a recognized variable
    }
}

Then, you could specify it in a variable-resolver directive, such as:

<?variable-resolver class="foo.CustomerResolve"?>

<listbox>
    <listitem label="${each.name}" forEach="${customers}"/>
</listbox>

System-level Variable Resolver

If you have a variable resolver that will be used on every page, you can register a system-level variable resolver rather than specifying it on every page.

This can be done by specifying a variable resolver you have implemented in WEB-INF/zk.xml as follows. For more information, please refer to ZK Configuration Reference.

<listener>
    <listener-class>foo.MyVariableResolver</listener-class>
</listener>

Then, when a page is created each time, an instance of the specified class will be instantiated and registered as if it is specified in the variable-resolver element.

Notice that since a new instance of the variable resolver is created on each page, there will not be any concurrency issues.

Calling Java Methods

Define in Page-Scope

The collection object could be retrieved by invoking a static method. For example, suppose that we have a class and a static method as follows:

package foo;
public class Customer {
    public static Collection<Customer> getAll(String condition) {
        //...returns a collection of customers
    }
    public String getName() {
       return _name;
    }
    //...
}

Then, we could retrieve them with the xel-method directive:

<?xel-method prefix="c" name="getAllCustomers" class="foo.Customer"
   signature="java.util.Collection getAll(java.lang.String)"?><!-- Generics not allowed -->
<listbox>
    <listitem label="${each.name}" forEach="${c:getAllCustomers('*')}"/>
</listbox>

Define as a Tag Library

If you have several static methods, you can declare them in an XML file called taglib, such as

<taglib>
	<function>
		<name>getAllCustomers</name>
		<function-class>foo.Customer</function-class>
		<function-signature>
	java.util.Collection getAll(java.lang.String)
		</function-signature>
		<description>
	Returns a collection of customers.
		</description>
	</function>
	<!-- any number of functions are allowed -->
</taglib>

Then, you can use them by specifying it in a taglib directive.

<?taglib uri="/WEB-INF/tld/my.tld" prefix="my"?>
<listbox>
    <listitem label="${each.name}" forEach="${my:getAllCustomers('*')}"/>
</listbox>

EL 3.0 Support

Since ZK 8, ZK supports some syntaxes of Java EE 7 Expression Language 3, see examples.




Last Update : 2024/02/06

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