New Features of ZK 8.0.0"
Tmillsclare (talk | contribs) m (Created page with "{{Template:Smalltalk_Author| |author=Timothy Clare, Potix Corporation |date=November 26, 2013 |version=ZK 7.0.0 }} = Introduction = The ZK team is proud to announce the releas...") |
m (correct highlight (via JWB)) |
||
(104 intermediate revisions by 4 users not shown) | |||
Line 1: | Line 1: | ||
{{Template:Smalltalk_Author| | {{Template:Smalltalk_Author| | ||
|author=Timothy Clare, Potix Corporation | |author=Timothy Clare, Potix Corporation | ||
− | |date= | + | |date=May, 2015 |
− | |version=ZK | + | |version=ZK 8.0.0 RC |
}} | }} | ||
Line 8: | Line 8: | ||
= Introduction = | = Introduction = | ||
− | The ZK team is proud to announce the release of ZK | + | The ZK team is proud to announce the release of ZK 8! |
− | ZK | + | ZK 8's main focus is on providing developers even more powerful tools allowing faster and more accurate development of Java Web Applications. We are proud to announce extensive improvement to EL, now supporting EL3, major MVVM enhancements and many more changes. |
− | |||
− | |||
− | |||
== Download and Demo == | == Download and Demo == | ||
Line 25: | Line 22: | ||
<br /> | <br /> | ||
+ | =Support Expression Language 3 (EL3)= | ||
+ | {{ZK All}} | ||
+ | |||
+ | introduce the new generation expression language of Java EE 7 – Expression Language 3 (EL 3) into ZK 8 so we can do more complicated and more powerful things with the newer expression language. There are many new features in EL 3 such as new operators, lambda expressions and collection operations. For more information on EL3 please take a look at the specification, [https://jcp.org/aboutJava/communityprocess/final/jsr341/index.html JSR-341]. | ||
+ | |||
+ | Please note that EL3 and all its features (including Lambda expressions) work for JDK 5 and above. | ||
+ | |||
+ | ==Lambda Expressions== | ||
+ | |||
+ | Each converter is implemented with the capability to interpret lambda expressions defined in zul. The following shows an example of a textbox who's value and onOK command are both driven by lambdas. | ||
+ | |||
+ | <source lang="xml"> | ||
+ | <textbox value="@load((x -> (x * 100) / 2.54)(vm.value))" | ||
+ | onOK="@command('click', key=((x -> (x * 2.54) / 100)(self.value)))" /> | ||
+ | </source> | ||
+ | |||
+ | The syntax used is same as ones in Java SE 8 and behaves like an anonymous function which is discarded after evaluated. We can name a lambda and evaluate indirectly. | ||
+ | |||
+ | Let us take the lambda expression (x -> (x * 100) / 2.54). In this case it will create an anonymous function which takes a value, multiplies it by 100 and divides the result by 2.54. This function is then applied to vm.value, where vm stands for our viewmodel. | ||
+ | |||
+ | To simplify this let us write some psuedo code for demonstration purposes. | ||
+ | |||
+ | <source lang="xml"> | ||
+ | myFunction = x -> (x * 100) / 2.54 //assign a lambda to myFunction temporarily | ||
+ | myFunction(vm.value) //execute myFunction passing vm.value as the parameter | ||
+ | </source> | ||
+ | |||
+ | While the above is just pseudo code to better help you understand the functionality it does demonstrate naming of lambdas, which is also possible. The following section outlines how to do this using two new operators. | ||
+ | |||
+ | ==New Operators== | ||
+ | |||
+ | ===String Concatenation=== | ||
+ | |||
+ | String concatenation has been introduced to make it easy to construct strings within EL expressions. The following code snippet demonstrates how to do so. | ||
+ | |||
+ | <source lang="xml"> | ||
+ | <label value="@load(('Hi, ' += vm.firstname += ' ' += vm.lastname))" /> | ||
+ | </source> | ||
+ | |||
+ | ===Assignment and Semicolons=== | ||
+ | |||
+ | Both assignment and semicolon operators are now implemented. Below shows an example of both being used. | ||
+ | |||
+ | <source lang="xml"> | ||
+ | <label value="@load((incr = x -> x + 1; incr(5)))" /> | ||
+ | </source> | ||
+ | |||
+ | The assignment operator in this instance assigns a lambda function to incr which takes x, increments by 1 and then returns it. | ||
+ | |||
+ | <source lang="xml"> | ||
+ | incr = x -> x + 1 | ||
+ | </source> | ||
+ | |||
+ | By using the ';' operator it evaluates the left hand side first, thus creating a lambda function incr, as previously discussed. Then evaluates and returns the right hand side. So in the following case: | ||
+ | |||
+ | <source lang="xml"> | ||
+ | <label value="@load((incr = x -> x + 1; incr(5)))" /> | ||
+ | </source> | ||
+ | |||
+ | The value assigned to the label would be 6, as the lambda function is first evaluated and assigned to incr, then the incr(5) call is evaluated leading to a return value of 6. | ||
+ | |||
+ | |||
+ | ==Collection Operations== | ||
+ | |||
+ | In ZK 8 it is now possible to use collection chain operations directly. In the example below we turn vm.names into stream() and then can create a pipeline of commands. | ||
+ | |||
+ | <source lang="xml"> | ||
+ | <listbox model="@load((vm.names.stream() | ||
+ | .filter(x -> x.contains(vm.filter)) | ||
+ | .toList()))"> | ||
+ | </source> | ||
+ | |||
+ | In addition to pipelines ZK 8's EL 3 supports easy collection construction using brackets (<nowiki>[ ]</nowiki>). The following example demonstrates this. | ||
+ | |||
+ | <source lang="xml"> | ||
+ | <label value="@load(([1, 2, 3, 4].stream().sum()))" /> | ||
+ | </source> | ||
+ | |||
+ | |||
+ | ==Static Field and Method References== | ||
+ | |||
+ | A static field or static method of a Java class can be referenced with the syntax Classname.Field, such as | ||
+ | |||
+ | <source lang="xml"> | ||
+ | <label value="@load((Math.sqrt(16)))" /> | ||
+ | </source> | ||
+ | |||
+ | Please note that java.lang.* is imported by default. | ||
+ | |||
+ | =Major MVVM Enhancements= | ||
+ | |||
+ | ==Performance Increase== | ||
+ | {{ZK EE}} | ||
+ | |||
+ | |||
+ | ZK 8 has brought about increases in MVVM binding performance, with both a memory consumption decrease and a response time increase. Below is the graph outlining these performance changes. | ||
+ | |||
+ | ===Memory improvements=== | ||
+ | |||
+ | ZK 8.0.0 RC requires much less memory than ZK 7.0.5 EE giving your application a boost just by upgrading. The graph plots the number of users against the memory used, where the '''lower the better'''. | ||
+ | |||
+ | [[File:memory-improvement.png|500px]] | ||
+ | |||
+ | ===Response Improvements=== | ||
+ | |||
+ | ZK 8.0.0 RC MVVM also responds quicker than ZK 7.0.5 EE. The graph below plots the number of users against the response time, where '''the lower the response time the better'''. | ||
+ | |||
+ | [[File:response-improvement.png|500px]] | ||
+ | |||
+ | |||
+ | ===Recreating the tests=== | ||
+ | |||
+ | If you would like to recreate these tests above in your environment you can use the following code: | ||
+ | |||
+ | '''Java code''' | ||
+ | |||
+ | <source lang="java"> | ||
+ | package org.zkoss.test; | ||
+ | |||
+ | import java.util.Collections; | ||
+ | import java.util.List; | ||
+ | |||
+ | public class ForEachVM { | ||
+ | private List<Integer> array = Collections.nCopies(30, 30); | ||
+ | public void setArray(List<Integer> array) {} | ||
+ | public List<Integer> getArray() { | ||
+ | return array; | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | '''ZUL''' | ||
+ | |||
+ | <source lang="xml"> | ||
+ | <zk xmlns:x="xhtml"> | ||
+ | <div id="bind" apply="org.zkoss.bind.BindComposer" | ||
+ | viewModel="@id('vm') @init('org.zkoss.test.ForEachVM')"> | ||
+ | <div style="display:none" id="host"> | ||
+ | <div children="@load(vm.array)"> | ||
+ | <template name="children"> | ||
+ | <div children="@load(vm.array)"> | ||
+ | <template name="children"> | ||
+ | Test Label | ||
+ | </template> | ||
+ | </div> | ||
+ | </template> | ||
+ | </div> | ||
+ | </div> | ||
+ | </div> | ||
+ | </zk> | ||
+ | </source> | ||
+ | |||
+ | ==SmartNotifyChange== | ||
+ | {{ZK All}} | ||
+ | |||
+ | |||
+ | ZK 8 brings about a change to the notify system. You are all used to @NotifyChange, however, ZK 8 has a better way, @SmartNotifyChange. Essentially the usage is exactly the same as @NotifyChange, except it will only notify the binder when a value has changed, unlike @NotifyChange. Thus it is more performant. | ||
+ | |||
+ | The following shows some example code: | ||
+ | |||
+ | <source lang="java"> | ||
+ | public class OrderVM { | ||
+ | |||
+ | //other code... | ||
+ | |||
+ | //action command | ||
+ | @SmartNotifyChange({"selected","orders","messages"}) | ||
+ | @Command | ||
+ | public void newOrder(){ | ||
+ | Order order = new Order(); | ||
+ | getOrders().add(order); //add new order to order list | ||
+ | selected = order;//select the new one | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | For more information please consult the [http://books.zkoss.org/zk-mvvm-book/8.0/syntax/smartnotifychange.html ZK MVVM Reference] and the [http://blog.zkoss.org/index.php/2015/02/03/zk8-new-form-binding-approach/ new form binding blog]. | ||
+ | |||
+ | ==MVVM support at the client== | ||
+ | {{ZK All}} | ||
+ | |||
+ | |||
+ | After listening to feedback the ZK team has introduced functionality in ZK 8 which allows developers to access ViewModel properties at the client. The following couple of code snippets demonstrates how to use this functionality. | ||
+ | |||
+ | ===Publishing a command using native component or direct invocation=== | ||
+ | <source lang="xml"> | ||
+ | <xhtml:button n:onClick="@command('doClick', {key:value, key1:value1})"/> | ||
+ | </source> | ||
+ | |||
+ | <source lang="javascript"> | ||
+ | wgt.$binder().command('doClick', args); | ||
+ | </source> | ||
+ | |||
+ | ===Subscribing to commands=== | ||
+ | |||
+ | <source lang="javascript"> | ||
+ | wgt.$binder().after('commandName', callbackFuncation); | ||
+ | </source> | ||
+ | |||
+ | For more information please take a look at the [[Small_Talks/2015/February/ZK8_Series:_UI_Template_Injection#More_Advanced_Usage | ZK 8 Series Smalltalk]]. | ||
+ | |||
+ | ==BindingParam annotation supports converting from JSON to POJO automatically== | ||
+ | {{ZK EE}} | ||
+ | |||
+ | |||
+ | ZK 8 now supports the ability to convert JSON sent to ZK into objects at the server automatically. Consider this example. | ||
+ | |||
+ | <source lang="javascript"> | ||
+ | zkbind.$(someone).command('dataChange', {data:{title: "myData"}}); | ||
+ | </source> | ||
+ | |||
+ | The above code will send JSON data to the command function "dataChange", this can be automatically converted into an appropriate object using the BindingParam. | ||
+ | |||
+ | <source lang="java"> | ||
+ | public static class DataObject { | ||
+ | private String title; | ||
+ | public void setTitle(String title) { | ||
+ | this.title = title; | ||
+ | } | ||
+ | public String getTitle() {return title;} | ||
+ | } | ||
+ | |||
+ | @Command | ||
+ | public void dataChange(@BindingParam("data") DataObject data) { | ||
+ | // do something here. | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | For more information please visit [[ZK_Configuration_Reference/zk.xml/The_Library_Properties/org.zkoss.bind.jsonBindingParamConverter.class | ZK Configuration Reference]]. | ||
+ | |||
+ | ==Children binding supports list model== | ||
+ | {{ZK All}} | ||
+ | |||
+ | |||
+ | In ZK 8, children binding supports a ListModel! This means you can separate the View and Model by implementing ListModel, which is used to provide data. Additionally, when you add/update/remove the data in the model, the corresponding components in children binding will be re-rendered at the same time. | ||
+ | |||
+ | When using List in children binding, to update data you have to use @NotifyChange to notify the binder any property changes, and the whole rendered components in children binding will be re-rendered at the same time. | ||
+ | |||
+ | The following example outlines the usage. | ||
+ | |||
+ | <source lang="xml"> | ||
+ | <vlayout children="@load(vm.model)"> | ||
+ | <template name="children"> | ||
+ | ... | ||
+ | </template> | ||
+ | </vlayout> | ||
+ | </source> | ||
+ | |||
+ | <source lang="java"> | ||
+ | private ListModelList model = new ListModelList(); | ||
+ | ... | ||
+ | |||
+ | @Command | ||
+ | public void add_model() { | ||
+ | Product newProduct = new Product(++count, "Microwave oven", 999); | ||
+ | model.add(newProduct); | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | <gflash width="640" height="400">childbinding_listmodel_support.swf</gflash> | ||
+ | |||
+ | For more information please take a look at our [http://blog.zkoss.org/index.php/2015/02/25/zk8-more-powerful-data-binding-in-mvvm-chilldren-binding-support-listmodel/ blog series on ZK 8 data binding]. | ||
+ | |||
+ | ==FormattedTimeConverter introduced== | ||
+ | {{ZK All}} | ||
+ | |||
+ | |||
+ | ZK 8 has introduced a new converter named formattedTime. This makes it extremely easy to output a specific time using a specified format. The following shows an example of usage. | ||
+ | |||
+ | <source lang="xml"> | ||
+ | <label value="@load(item.time) @converter('formattedTime', format='hhmmss')"/> | ||
+ | </source> | ||
+ | |||
+ | For more information please [http://books.zkoss.org/zk-mvvm-book/8.0/data_binding/converter.html#use-built-in-converter refer to our ZK MVVM Reference]. | ||
+ | |||
+ | =New components & enhancements= | ||
+ | |||
+ | ==Lightweight rich editor== | ||
+ | {{ZK EE}} | ||
+ | |||
+ | ZK 8 introduces a brand new lightweight component called Tbeditor, representing the JavaScript component [http://alex-d.github.io/Trumbowyg/ Trumbowyg]. Tbeditor is a rich WYSIWYG text editor. | ||
+ | |||
+ | The following is an example of how to use Tbeditor in your application. | ||
+ | |||
+ | [[Image:Zkcompref tbeditor.png|800px]] | ||
+ | |||
+ | <source lang="xml" > | ||
+ | <tbeditor id="tb" value="this is a demo for <b>trumbowy</b> editor!!" /> | ||
+ | </source> | ||
+ | |||
+ | For more information please consult the [[ZK_Component_Reference/Input/Tbeditor | ZK Component Reference]]. | ||
+ | |||
+ | ==Timepicker Component== | ||
+ | {{ZK EE}} | ||
+ | |||
+ | ZK 8 introduces a new component to handle times. The component also has a lot of functionality such as minimum & maximum times along with formatting. | ||
+ | |||
+ | [[Image:ZKCompRef_Timepicker.png]] | ||
+ | |||
+ | |||
+ | <source lang="xml" > | ||
+ | <window title="Simple" width="300px" border="normal"> | ||
+ | <timebox id="tb0"/> | ||
+ | </window> | ||
+ | </source> | ||
+ | |||
+ | For more information please consult the [[ZK_Component_Reference/Input/Timepicker | ZK Component Reference]]. | ||
+ | |||
+ | ==Scrollview component== | ||
+ | {{ZK EE}} | ||
+ | |||
+ | |||
+ | The Scrollview component, first introduced in ZK 6.5 with mobile and tablet compatibility, is now also available on desktop. With the amazing infinite scrolling feature. | ||
+ | |||
+ | For example, | ||
+ | |||
+ | <source lang="xml"> | ||
+ | <zscript><![CDATA[ | ||
+ | public void append(Scrollview sv, int pos, boolean outBound) { | ||
+ | if (outBound && pos > 0) { | ||
+ | Window w = new Window("window end", "normal", false); | ||
+ | sv.appendChild(w); | ||
+ | } | ||
+ | } | ||
+ | ]]></zscript> | ||
+ | <scrollview id="sv" onScroll="append(self, event.pos, event.outOfBound)" orient="horizontal"> | ||
+ | <window title="window1" border="normal"> | ||
+ | This is Window 1 | ||
+ | </window> | ||
+ | </scrollview> | ||
+ | </source> | ||
+ | |||
+ | With that, users can scroll down endlessly. | ||
+ | |||
+ | Just like in the 6.5 version, this component also provides two events. | ||
+ | |||
+ | * onScroll | ||
+ | * onScrolling | ||
+ | |||
+ | The only difference is that in ZK 8.0, the onScroll event will be triggered when users scroll all the way to the top or to the end of the page. The onScrolling event remains the same as before. | ||
+ | |||
+ | |||
+ | For more information please consult the [[ZK_Component_Reference/Tablet_Devices/Components/Scrollview#Scrollview | ZK Component Reference]]. | ||
+ | |||
+ | ==Rowlayout== | ||
+ | {{ZK EE}} | ||
+ | |||
+ | ZK 8 introduces a new, powerful layout component named rowlayout which allows developers to place components inside a grid. This allows for flexible and simple layouts. The following diagram illustrates the rowlayout/rowchildren components and their various configurable parameters. | ||
+ | |||
+ | [[Image:ZKComRef_Rowlayout.PNG|600px]] | ||
+ | |||
+ | Using rowlayout component is simple. First, use rowlayout to divide the horizontal space of its parent container into a number of columns. You can also optionally specify the column/spacing ratio. The default number of columns is 12, and the default column/spacing ratio is 1/3, which means column is 3 times wider than the spacing between columns. Spacing could be given as a ratio, a percentage or a floating-point number. | ||
+ | |||
+ | A sample usage is demonstrated below. | ||
+ | |||
+ | <source lang="xml" > | ||
+ | <rowlayout ncols="12" spacing="1/3"> | ||
+ | <rowchildren colspan="3" offset="2"> | ||
+ | </rowchildren> | ||
+ | </rowlayout> | ||
+ | </source> | ||
+ | |||
+ | For more information please consult the [[ZK_Component_Reference/Layouts/Rowlayout | ZK Component Reference]]. | ||
+ | |||
+ | =Shadow Elements= | ||
+ | {{ZK_EE}} | ||
+ | |||
+ | ZK 8 introduces a new concept called '''Shadow Element'''. | ||
+ | |||
+ | In simple terms shadow elements help application developers to compose an html layout with some dynamic data. They are basically templates, however, with shadow elements it helps the application to manage templates and their implementation that are outside of the component tree. Thus a shadow element is not visible to users but is handled by ZK. | ||
+ | |||
+ | A web designer can pre-define a template based on HTML syntax for application developers to use. | ||
+ | |||
+ | For example, | ||
+ | |||
+ | <source lang="xml" highlight="2,4"> | ||
+ | <div> | ||
+ | <if test="${user.editable}"> | ||
+ | User Name: <textbox value="${user.name}"/> | ||
+ | <forEach items="${user.phones}" var="phone"> | ||
+ | <label value="${phone.number}"/> | ||
+ | </forEach> | ||
+ | </if> | ||
+ | </div> | ||
+ | </source> | ||
+ | |||
+ | [[File:Shadow_Diagram.PNG]] | ||
+ | |||
+ | As shown in the diagram above, the tree is separated into two parts - <i>'''Logical Tree'''</i> and <i>'''Composed Tree'''</i>. | ||
+ | * <b>Logical Tree</b> is created by ZK page parser to construct a page definition tree and then instantiate it into a "Composed Tree". | ||
+ | * <b>Composed Tree</b> is also separated into two parts, one is the component tree (green area) which is the same as before, and the other is the new concept (red area) <b><i>shadow tree</i></b>, which is not visible for application developers but component developers. | ||
+ | The shadow tree in the example above with EL expression won't be alive once the output is rendered to the client. This is because shadow elements are not applied with dynamic data such as ''@load'' expressions, so there is no reason to store them in the server side to burden the memory consumption. | ||
+ | |||
+ | |||
+ | ==Example== | ||
+ | |||
+ | To give an example of the power available, the following demo outlines the an application using 3 dataviews (grid, list and tree) using the same dataset and codebase. | ||
+ | |||
+ | <gflash width="900" height="760">2015-02-04_1629.swf</gflash> | ||
+ | |||
+ | |||
+ | To fully understand the power of shadow components, please refer to the [[Small_Talks/2015/February/ZK8_Series:_UI_Template_Injection | ZK 8 Series Smalltalk]]. | ||
+ | |||
+ | =Custom data attribute handlers are now possible= | ||
+ | {{ZK All}} | ||
+ | |||
+ | |||
+ | It is possible to define custom data-handlers for client attributes which gives extra flexibility to developers looking to integrate with, and use, 3rd party libraries. | ||
+ | |||
+ | For example, the following demonstrates a data-handler for jQuery's mask functionality. | ||
+ | |||
+ | |||
+ | '''Zul File:''' | ||
+ | <source lang="xml"> | ||
+ | <textbox xmlns:ca="client/attribute" ca:data-mask="00:00:00" onChange='Clients.log(self.value)'/> | ||
+ | </source> | ||
+ | |||
+ | '''zk.xml:''' | ||
+ | <source lang="xml"> | ||
+ | <client-config> | ||
+ | <data-handler> | ||
+ | <name>mask</name><!-- the attribute name, i.e. data-mask --> | ||
+ | <depends>http://igorescobar.github.io/jQuery-Mask-Plugin/js/jquery.mask.min.js</depends> | ||
+ | <script> | ||
+ | function (wgt, dataValue) { | ||
+ | jq(wgt.$n()).mask(dataValue); | ||
+ | |||
+ | // unformat after onChange event. | ||
+ | wgt.listen({onChange: function (event) { | ||
+ | event.data.value = jq(this.$n()).cleanVal(); | ||
+ | }}); | ||
+ | } | ||
+ | </script> | ||
+ | </data-handler> | ||
+ | </client-config> | ||
+ | </source> | ||
+ | |||
+ | For more information please refer to the [[ZUML_Reference/ZUML/Namespaces/Client_Attribute | ZK ZUML Reference]]. | ||
+ | |||
+ | =Font Awesome upgrade= | ||
+ | {{ZK All}} | ||
+ | |||
+ | |||
+ | Font awesome has been upgraded to version 4.3, introducing over 40 new icons. For more details please check the [http://fortawesome.github.io/Font-Awesome/icons/ font-awesome website]. | ||
+ | |||
+ | =Introduced Danish language support= | ||
+ | {{ZK All}} | ||
+ | |||
+ | |||
+ | Thanks to our contributor XXXX ZK 8 now provides support for the Danish language. | ||
+ | |||
+ | =Other changes= | ||
+ | |||
+ | ==ZHTML component's src attribute supports encoded url in ZUL== | ||
+ | {{ZK All}} | ||
+ | |||
+ | ZK 8's ZHTML components now support encoded urls, this makes it much easier to specify images and other urls on the src attribute. | ||
+ | |||
+ | For example: | ||
+ | |||
+ | <source lang="xml"> | ||
+ | <x:img xmlns:x="xhtml" src="~./img/spacer.gif" xmlns:c="client" c:onBind='zk.log(this.$n().src)'/> | ||
+ | </source> | ||
+ | |||
+ | For more information please refer to the [http://books.zkoss.org/wiki/ZK_Component_Reference/XHTML_Components ZK Component Reference]. | ||
+ | |||
+ | ==ZHTML supports dynamic data binding== | ||
+ | {{ZK All}} | ||
+ | |||
+ | |||
+ | The textContent attribute now supports dynamic databinding, meaning it is now possible to use MVVM based commands for a textContent attribute. For example: | ||
+ | |||
+ | <source lang="xml"> | ||
+ | <label textContent="@load(each.author.name)" | ||
+ | sclass="author-name z-label" /> | ||
+ | </source> | ||
+ | |||
+ | ==Simplified thrown exceptions== | ||
+ | {{ZK All}} | ||
+ | |||
+ | Exceptions were thrown as UIExceptions and when including templates or similar procedures the resulting stacktrace was exceptionally hard to follow. This also make it difficult to create meaningful error pages for application. | ||
+ | |||
+ | With the advent of ZK 8 this is now gone and exceptions are not wrapped with UIException, they will throw a RuntimeException. | ||
+ | |||
+ | ==Multiple custom error messages supported for multiple constraints== | ||
+ | {{ZK All}} | ||
+ | |||
+ | Previously when defining constraints only the last constraint could have a separate error message. This has now been rectified and every constraint can have its own custom error message. | ||
+ | |||
+ | For example: | ||
+ | |||
+ | <source lang="xml"> | ||
+ | <datebox constraint="no empty: please select a date, no future: now or never" /> | ||
+ | </source> | ||
+ | |||
+ | For more information please refer to [[ZK_Component_Reference/Base_Components/InputElement | ZK's Component Reference]]. | ||
+ | |||
+ | ==Datebox calendar now contains a today button== | ||
+ | {{ZK All}} | ||
+ | |||
+ | Since ZK 8 the Datebox calendar now contains a button which can easily reset the date to today. The button takes on the form of the current date. | ||
+ | |||
+ | [[Image:ZKComRef_Datebox_Link_Of_Today.PNG]] | ||
+ | |||
+ | ==Embedded types now allowed== | ||
+ | {{ZK All}} | ||
+ | |||
+ | When parsing a page sometimes an error would occur when HTML was embedded in a ZHTML page. This is now fixed and the ability to use different parsers depending on the syntax in the page is allowed. | ||
+ | |||
+ | For example, here we have HTML embedded inside ZHTML, no exception will be thrown. | ||
+ | |||
+ | <source lang="xml"> | ||
+ | <html> | ||
+ | <head> | ||
+ | <!--[if lte IE 9]> | ||
+ | <link rel="stylesheet" href="../assets/css/test.min.css" /> | ||
+ | <![endif]--> | ||
+ | </head> | ||
+ | <body> | ||
+ | <u:window xmlns:u="zul" title="test" id="mainWindow" apply="org.zkoss.bind.BindComposer" | ||
+ | viewModel="@id('vm') @init('test.MyVM')" height="100%" width="100%"> | ||
+ | © Test | ||
+ | </u:window> | ||
+ | </body> | ||
+ | </html> | ||
+ | </source> | ||
+ | |||
+ | ==ForeachStatus is consistent with JSTL's varStatus properties== | ||
+ | {{ZK All}} | ||
+ | |||
+ | ZK's ForEachStatus now has the same properties as varStatus, so it is more intuitive for developers to use as it is what they are used to. | ||
+ | <source lang="xml"> | ||
+ | <zk xmlns:n="native"> | ||
+ | <n:h4>1. Test case: forEach="one, two, three, four"</n:h4> | ||
+ | <zscript> | ||
+ | items = Arrays.asList(new Object[] { "one", "two", "three", "four" }); | ||
+ | </zscript> | ||
+ | <div style="border:1px solid blue"> | ||
+ | <div forEach="${items}"> | ||
+ | ${each} Index: ${forEachStatus.index} Count: | ||
+ | ${forEachStatus.count} First: ${forEachStatus.first} Last: | ||
+ | ${forEachStatus.last} | ||
+ | </div> | ||
+ | </div> | ||
+ | Result: | ||
+ | <div style="border:1px solid red;color:blue"> | ||
+ | <div>one Index: 0 Count: 1 First: true Last: false</div> | ||
+ | <div>two Index: 1 Count: 2 First: false Last: false</div> | ||
+ | <div>three Index: 2 Count: 3 First: false Last: false</div> | ||
+ | <div>four Index: 3 Count: 4 First: false Last: true</div> | ||
+ | </div> | ||
+ | <n:h4>2. Test case: forEach="one, two, three, four" forEachStep="3"</n:h4> | ||
+ | <div style="border:1px solid blue"> | ||
+ | <div forEach="${items}" forEachStep="3"> | ||
+ | ${each} Index: ${forEachStatus.index} Count: | ||
+ | ${forEachStatus.count} First: ${forEachStatus.first} Last: | ||
+ | ${forEachStatus.last} | ||
+ | </div> | ||
+ | </div> | ||
+ | Result: | ||
+ | <div style="border:1px solid red;color:blue"> | ||
+ | <div>one Index: 0 Count: 1 First: true Last: false</div> | ||
+ | <div>four Index: 3 Count: 2 First: false Last: true</div> | ||
+ | </div> | ||
+ | <n:h4>3. Test case: forEach="one, two, three, four" forEachBegin="1" forEachStep="3" | ||
+ | </n:h4> | ||
+ | <div style="border:1px solid blue"> | ||
+ | <div forEach="${items}" forEachBegin="1" forEachStep="3"> | ||
+ | ${each} Index: ${forEachStatus.index} Count: | ||
+ | ${forEachStatus.count} First: ${forEachStatus.first} Last: | ||
+ | ${forEachStatus.last} | ||
+ | </div> | ||
+ | </div> | ||
+ | Result: | ||
+ | <div style="border:1px solid red;color:blue"> | ||
+ | <div>two Index: 1 Count: 1 First: true Last: true</div> | ||
+ | </div> | ||
+ | </zk> | ||
+ | </source> | ||
Latest revision as of 04:21, 20 January 2022
Timothy Clare, Potix Corporation
May, 2015
ZK 8.0.0 RC
Introduction
The ZK team is proud to announce the release of ZK 8!
ZK 8's main focus is on providing developers even more powerful tools allowing faster and more accurate development of Java Web Applications. We are proud to announce extensive improvement to EL, now supporting EL3, major MVVM enhancements and many more changes.
Download and Demo
Support Expression Language 3 (EL3)
- Available for ZK:
introduce the new generation expression language of Java EE 7 – Expression Language 3 (EL 3) into ZK 8 so we can do more complicated and more powerful things with the newer expression language. There are many new features in EL 3 such as new operators, lambda expressions and collection operations. For more information on EL3 please take a look at the specification, JSR-341.
Please note that EL3 and all its features (including Lambda expressions) work for JDK 5 and above.
Lambda Expressions
Each converter is implemented with the capability to interpret lambda expressions defined in zul. The following shows an example of a textbox who's value and onOK command are both driven by lambdas.
<textbox value="@load((x -> (x * 100) / 2.54)(vm.value))"
onOK="@command('click', key=((x -> (x * 2.54) / 100)(self.value)))" />
The syntax used is same as ones in Java SE 8 and behaves like an anonymous function which is discarded after evaluated. We can name a lambda and evaluate indirectly.
Let us take the lambda expression (x -> (x * 100) / 2.54). In this case it will create an anonymous function which takes a value, multiplies it by 100 and divides the result by 2.54. This function is then applied to vm.value, where vm stands for our viewmodel.
To simplify this let us write some psuedo code for demonstration purposes.
myFunction = x -> (x * 100) / 2.54 //assign a lambda to myFunction temporarily
myFunction(vm.value) //execute myFunction passing vm.value as the parameter
While the above is just pseudo code to better help you understand the functionality it does demonstrate naming of lambdas, which is also possible. The following section outlines how to do this using two new operators.
New Operators
String Concatenation
String concatenation has been introduced to make it easy to construct strings within EL expressions. The following code snippet demonstrates how to do so.
<label value="@load(('Hi, ' += vm.firstname += ' ' += vm.lastname))" />
Assignment and Semicolons
Both assignment and semicolon operators are now implemented. Below shows an example of both being used.
<label value="@load((incr = x -> x + 1; incr(5)))" />
The assignment operator in this instance assigns a lambda function to incr which takes x, increments by 1 and then returns it.
incr = x -> x + 1
By using the ';' operator it evaluates the left hand side first, thus creating a lambda function incr, as previously discussed. Then evaluates and returns the right hand side. So in the following case:
<label value="@load((incr = x -> x + 1; incr(5)))" />
The value assigned to the label would be 6, as the lambda function is first evaluated and assigned to incr, then the incr(5) call is evaluated leading to a return value of 6.
Collection Operations
In ZK 8 it is now possible to use collection chain operations directly. In the example below we turn vm.names into stream() and then can create a pipeline of commands.
<listbox model="@load((vm.names.stream()
.filter(x -> x.contains(vm.filter))
.toList()))">
In addition to pipelines ZK 8's EL 3 supports easy collection construction using brackets ([ ]). The following example demonstrates this.
<label value="@load(([1, 2, 3, 4].stream().sum()))" />
Static Field and Method References
A static field or static method of a Java class can be referenced with the syntax Classname.Field, such as
<label value="@load((Math.sqrt(16)))" />
Please note that java.lang.* is imported by default.
Major MVVM Enhancements
Performance Increase
- Available for ZK:
ZK 8 has brought about increases in MVVM binding performance, with both a memory consumption decrease and a response time increase. Below is the graph outlining these performance changes.
Memory improvements
ZK 8.0.0 RC requires much less memory than ZK 7.0.5 EE giving your application a boost just by upgrading. The graph plots the number of users against the memory used, where the lower the better.
Response Improvements
ZK 8.0.0 RC MVVM also responds quicker than ZK 7.0.5 EE. The graph below plots the number of users against the response time, where the lower the response time the better.
Recreating the tests
If you would like to recreate these tests above in your environment you can use the following code:
Java code
package org.zkoss.test;
import java.util.Collections;
import java.util.List;
public class ForEachVM {
private List<Integer> array = Collections.nCopies(30, 30);
public void setArray(List<Integer> array) {}
public List<Integer> getArray() {
return array;
}
}
ZUL
<zk xmlns:x="xhtml">
<div id="bind" apply="org.zkoss.bind.BindComposer"
viewModel="@id('vm') @init('org.zkoss.test.ForEachVM')">
<div style="display:none" id="host">
<div children="@load(vm.array)">
<template name="children">
<div children="@load(vm.array)">
<template name="children">
Test Label
</template>
</div>
</template>
</div>
</div>
</div>
</zk>
SmartNotifyChange
- Available for ZK:
ZK 8 brings about a change to the notify system. You are all used to @NotifyChange, however, ZK 8 has a better way, @SmartNotifyChange. Essentially the usage is exactly the same as @NotifyChange, except it will only notify the binder when a value has changed, unlike @NotifyChange. Thus it is more performant.
The following shows some example code:
public class OrderVM {
//other code...
//action command
@SmartNotifyChange({"selected","orders","messages"})
@Command
public void newOrder(){
Order order = new Order();
getOrders().add(order); //add new order to order list
selected = order;//select the new one
}
}
For more information please consult the ZK MVVM Reference and the new form binding blog.
MVVM support at the client
- Available for ZK:
After listening to feedback the ZK team has introduced functionality in ZK 8 which allows developers to access ViewModel properties at the client. The following couple of code snippets demonstrates how to use this functionality.
Publishing a command using native component or direct invocation
<xhtml:button n:onClick="@command('doClick', {key:value, key1:value1})"/>
wgt.$binder().command('doClick', args);
Subscribing to commands
wgt.$binder().after('commandName', callbackFuncation);
For more information please take a look at the ZK 8 Series Smalltalk.
BindingParam annotation supports converting from JSON to POJO automatically
- Available for ZK:
ZK 8 now supports the ability to convert JSON sent to ZK into objects at the server automatically. Consider this example.
zkbind.$(someone).command('dataChange', {data:{title: "myData"}});
The above code will send JSON data to the command function "dataChange", this can be automatically converted into an appropriate object using the BindingParam.
public static class DataObject {
private String title;
public void setTitle(String title) {
this.title = title;
}
public String getTitle() {return title;}
}
@Command
public void dataChange(@BindingParam("data") DataObject data) {
// do something here.
}
For more information please visit ZK Configuration Reference.
Children binding supports list model
- Available for ZK:
In ZK 8, children binding supports a ListModel! This means you can separate the View and Model by implementing ListModel, which is used to provide data. Additionally, when you add/update/remove the data in the model, the corresponding components in children binding will be re-rendered at the same time.
When using List in children binding, to update data you have to use @NotifyChange to notify the binder any property changes, and the whole rendered components in children binding will be re-rendered at the same time.
The following example outlines the usage.
<vlayout children="@load(vm.model)">
<template name="children">
...
</template>
</vlayout>
private ListModelList model = new ListModelList();
...
@Command
public void add_model() {
Product newProduct = new Product(++count, "Microwave oven", 999);
model.add(newProduct);
}
For more information please take a look at our blog series on ZK 8 data binding.
FormattedTimeConverter introduced
- Available for ZK:
ZK 8 has introduced a new converter named formattedTime. This makes it extremely easy to output a specific time using a specified format. The following shows an example of usage.
<label value="@load(item.time) @converter('formattedTime', format='hhmmss')"/>
For more information please refer to our ZK MVVM Reference.
New components & enhancements
Lightweight rich editor
- Available for ZK:
ZK 8 introduces a brand new lightweight component called Tbeditor, representing the JavaScript component Trumbowyg. Tbeditor is a rich WYSIWYG text editor.
The following is an example of how to use Tbeditor in your application.
<tbeditor id="tb" value="this is a demo for <b>trumbowy</b> editor!!" />
For more information please consult the ZK Component Reference.
Timepicker Component
- Available for ZK:
ZK 8 introduces a new component to handle times. The component also has a lot of functionality such as minimum & maximum times along with formatting.
<window title="Simple" width="300px" border="normal">
<timebox id="tb0"/>
</window>
For more information please consult the ZK Component Reference.
Scrollview component
- Available for ZK:
The Scrollview component, first introduced in ZK 6.5 with mobile and tablet compatibility, is now also available on desktop. With the amazing infinite scrolling feature.
For example,
<zscript><![CDATA[
public void append(Scrollview sv, int pos, boolean outBound) {
if (outBound && pos > 0) {
Window w = new Window("window end", "normal", false);
sv.appendChild(w);
}
}
]]></zscript>
<scrollview id="sv" onScroll="append(self, event.pos, event.outOfBound)" orient="horizontal">
<window title="window1" border="normal">
This is Window 1
</window>
</scrollview>
With that, users can scroll down endlessly.
Just like in the 6.5 version, this component also provides two events.
- onScroll
- onScrolling
The only difference is that in ZK 8.0, the onScroll event will be triggered when users scroll all the way to the top or to the end of the page. The onScrolling event remains the same as before.
For more information please consult the ZK Component Reference.
Rowlayout
- Available for ZK:
ZK 8 introduces a new, powerful layout component named rowlayout which allows developers to place components inside a grid. This allows for flexible and simple layouts. The following diagram illustrates the rowlayout/rowchildren components and their various configurable parameters.
Using rowlayout component is simple. First, use rowlayout to divide the horizontal space of its parent container into a number of columns. You can also optionally specify the column/spacing ratio. The default number of columns is 12, and the default column/spacing ratio is 1/3, which means column is 3 times wider than the spacing between columns. Spacing could be given as a ratio, a percentage or a floating-point number.
A sample usage is demonstrated below.
<rowlayout ncols="12" spacing="1/3">
<rowchildren colspan="3" offset="2">
</rowchildren>
</rowlayout>
For more information please consult the ZK Component Reference.
Shadow Elements
- Available for ZK:
ZK 8 introduces a new concept called Shadow Element.
In simple terms shadow elements help application developers to compose an html layout with some dynamic data. They are basically templates, however, with shadow elements it helps the application to manage templates and their implementation that are outside of the component tree. Thus a shadow element is not visible to users but is handled by ZK.
A web designer can pre-define a template based on HTML syntax for application developers to use.
For example,
<div>
<if test="${user.editable}">
User Name: <textbox value="${user.name}"/>
<forEach items="${user.phones}" var="phone">
<label value="${phone.number}"/>
</forEach>
</if>
</div>
As shown in the diagram above, the tree is separated into two parts - Logical Tree and Composed Tree.
- Logical Tree is created by ZK page parser to construct a page definition tree and then instantiate it into a "Composed Tree".
- Composed Tree is also separated into two parts, one is the component tree (green area) which is the same as before, and the other is the new concept (red area) shadow tree, which is not visible for application developers but component developers.
The shadow tree in the example above with EL expression won't be alive once the output is rendered to the client. This is because shadow elements are not applied with dynamic data such as @load expressions, so there is no reason to store them in the server side to burden the memory consumption.
Example
To give an example of the power available, the following demo outlines the an application using 3 dataviews (grid, list and tree) using the same dataset and codebase.
To fully understand the power of shadow components, please refer to the ZK 8 Series Smalltalk.
Custom data attribute handlers are now possible
- Available for ZK:
It is possible to define custom data-handlers for client attributes which gives extra flexibility to developers looking to integrate with, and use, 3rd party libraries.
For example, the following demonstrates a data-handler for jQuery's mask functionality.
Zul File:
<textbox xmlns:ca="client/attribute" ca:data-mask="00:00:00" onChange='Clients.log(self.value)'/>
zk.xml:
<client-config>
<data-handler>
<name>mask</name><!-- the attribute name, i.e. data-mask -->
<depends>http://igorescobar.github.io/jQuery-Mask-Plugin/js/jquery.mask.min.js</depends>
<script>
function (wgt, dataValue) {
jq(wgt.$n()).mask(dataValue);
// unformat after onChange event.
wgt.listen({onChange: function (event) {
event.data.value = jq(this.$n()).cleanVal();
}});
}
</script>
</data-handler>
</client-config>
For more information please refer to the ZK ZUML Reference.
Font Awesome upgrade
- Available for ZK:
Font awesome has been upgraded to version 4.3, introducing over 40 new icons. For more details please check the font-awesome website.
Introduced Danish language support
- Available for ZK:
Thanks to our contributor XXXX ZK 8 now provides support for the Danish language.
Other changes
ZHTML component's src attribute supports encoded url in ZUL
- Available for ZK:
ZK 8's ZHTML components now support encoded urls, this makes it much easier to specify images and other urls on the src attribute.
For example:
<x:img xmlns:x="xhtml" src="~./img/spacer.gif" xmlns:c="client" c:onBind='zk.log(this.$n().src)'/>
For more information please refer to the ZK Component Reference.
ZHTML supports dynamic data binding
- Available for ZK:
The textContent attribute now supports dynamic databinding, meaning it is now possible to use MVVM based commands for a textContent attribute. For example:
<label textContent="@load(each.author.name)"
sclass="author-name z-label" />
Simplified thrown exceptions
- Available for ZK:
Exceptions were thrown as UIExceptions and when including templates or similar procedures the resulting stacktrace was exceptionally hard to follow. This also make it difficult to create meaningful error pages for application.
With the advent of ZK 8 this is now gone and exceptions are not wrapped with UIException, they will throw a RuntimeException.
Multiple custom error messages supported for multiple constraints
- Available for ZK:
Previously when defining constraints only the last constraint could have a separate error message. This has now been rectified and every constraint can have its own custom error message.
For example:
<datebox constraint="no empty: please select a date, no future: now or never" />
For more information please refer to ZK's Component Reference.
Datebox calendar now contains a today button
- Available for ZK:
Since ZK 8 the Datebox calendar now contains a button which can easily reset the date to today. The button takes on the form of the current date.
Embedded types now allowed
- Available for ZK:
When parsing a page sometimes an error would occur when HTML was embedded in a ZHTML page. This is now fixed and the ability to use different parsers depending on the syntax in the page is allowed.
For example, here we have HTML embedded inside ZHTML, no exception will be thrown.
<html>
<head>
<!--[if lte IE 9]>
<link rel="stylesheet" href="../assets/css/test.min.css" />
<![endif]-->
</head>
<body>
<u:window xmlns:u="zul" title="test" id="mainWindow" apply="org.zkoss.bind.BindComposer"
viewModel="@id('vm') @init('test.MyVM')" height="100%" width="100%">
© Test
</u:window>
</body>
</html>
ForeachStatus is consistent with JSTL's varStatus properties
- Available for ZK:
ZK's ForEachStatus now has the same properties as varStatus, so it is more intuitive for developers to use as it is what they are used to.
<zk xmlns:n="native">
<n:h4>1. Test case: forEach="one, two, three, four"</n:h4>
<zscript>
items = Arrays.asList(new Object[] { "one", "two", "three", "four" });
</zscript>
<div style="border:1px solid blue">
<div forEach="${items}">
${each} Index: ${forEachStatus.index} Count:
${forEachStatus.count} First: ${forEachStatus.first} Last:
${forEachStatus.last}
</div>
</div>
Result:
<div style="border:1px solid red;color:blue">
<div>one Index: 0 Count: 1 First: true Last: false</div>
<div>two Index: 1 Count: 2 First: false Last: false</div>
<div>three Index: 2 Count: 3 First: false Last: false</div>
<div>four Index: 3 Count: 4 First: false Last: true</div>
</div>
<n:h4>2. Test case: forEach="one, two, three, four" forEachStep="3"</n:h4>
<div style="border:1px solid blue">
<div forEach="${items}" forEachStep="3">
${each} Index: ${forEachStatus.index} Count:
${forEachStatus.count} First: ${forEachStatus.first} Last:
${forEachStatus.last}
</div>
</div>
Result:
<div style="border:1px solid red;color:blue">
<div>one Index: 0 Count: 1 First: true Last: false</div>
<div>four Index: 3 Count: 2 First: false Last: true</div>
</div>
<n:h4>3. Test case: forEach="one, two, three, four" forEachBegin="1" forEachStep="3"
</n:h4>
<div style="border:1px solid blue">
<div forEach="${items}" forEachBegin="1" forEachStep="3">
${each} Index: ${forEachStatus.index} Count:
${forEachStatus.count} First: ${forEachStatus.first} Last:
${forEachStatus.last}
</div>
</div>
Result:
<div style="border:1px solid red;color:blue">
<div>two Index: 1 Count: 1 First: true Last: true</div>
</div>
</zk>
Comments
Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License. |