Karn: Declarative Data-binding for ZK
Abhishek Patnia, Creator of Karn, Software Development Engineer, Amazon.com - Reviewed by Dr. Gunther Schadow
September 08, 2009
Karn is a component package for ZK. This package brings declarative data-binding, centralized event handling mechanism and certain widgets enhancements to the ZK framework.
We provide two way declarative data-binding to link objects properties or database table attributes to user-interface elements in such a way that updates to the data on the server side are automatically displayed on the client side, and updates on the user-interface cause updates to the objects/tables on the server side. Without declarative data-binding, the developer must code these update actions for every field which can be very tedious. Declarative data-binding means that the connection between user-interface fields and object properties is specified in the GUI declaration.
For example in Karn we have introduced the following ZUML syntax for declarative data-binding
<window use="net.sf.karn.extendedComponent.ArjunWindow"> @comment:The param tag is used to connect to a model object. <param name="this" adapter="demo.viewAdapters.GenericViewAdapter" create="object" /> <data-binding> <textbox /> @comment:The data tag is used to connect an object property to a widget aspect. <data param="this" property="firstName" aspect="text" /> </data-binding> …………….. </window>
With the <databinding> tag we say that the following widget (textbox) is to be bound to the property “firstName” of the object referenced by the variable named “this”.
The variable “this” is declared with the <param> tag. As a parameter it may be “passed” by a parent view (“window” in ZK) or a default object may be created. The parameter “this” refers to a model object 2 and the property “firstName” refers to a property of that model object.
Karn ZUML Tags
<window use="net.sf.karn.extendedComponent.ArjunWindow"> @comment:The param tag is used to connect to a model object. <param name="this" adapter="demo.viewAdapters.PersonViewAdapter" create="object" /> <databinding> <textbox /> @comment:The data tag is used to connect an object property to a widget aspect. <data param="this" property="firstName" aspect="text" /> </databinding> …………….. </window>
While using Karn we need to start each new page with the Window tag and specify the use attribute so that ZK uses our own specialized window class.
The param tag
It can be thought of as a bridge between the Model Object 2and the View2. <param>Tag has various properties that are used to configure the access of a particular model object by the View. We specify the adapter as the fully qualified name of a java class that implements the ViewAdapter interface. Create specifies how the Model Object is created. For our example we just specify the “object” option, which means to create a new object. We can also use “lazy” which means to create a variable with reference to a Model Object only when the variable is used. The ”variable ” option is used to create a variable with reference to nothing. The databinding tag
Any widget that we want to use for data-binding must be the first child of the data-binding tag. It has 2 arguments (child XML tags), first the widget bound with that data and then tag binding the data to that widget. For example
<databinding> <textbox/> <data param=”this” aspect=”value” property=”age”/> </databinding>
Note that we would have preferred nesting the tags under the widget tag, but that would have required us to extend every single widget implementation to deal with the data-binding aspect. Hence we decided to wrap the widget in the <databinding> tag instead. Any ZK widget (or any extension widget) can be wrapped in this way.
The data tag
Data tag maps the properties of the model object to the aspect of the widgets.
We specify the name of the variable as the param attribute and the model object property as the property attribute. The property attribute generally refer to model object properties which are of a data type suitable to be rendered by that widget, e.g. usually String or sometimes integer or Date; but rarely are higher level objects bound to UI widgets.Aspect attribute as the aspect of the widget, that is, the text of a text box, or the tool-tip or another widget, or the “red”-value of a color picker, etc.
One data-binding tag can have more than one data tags, each binding a property to a different widget aspect. For example
<databinding> <slider/> <data param=”vitalSignParam” property=”value” aspect=”curpos”/> <data param=”vitalSignParam” property=”name” aspect=”label”/> </databinding>
Iterative rendering and Formatters
Whenever the model object has properties of multiplicity greater than 1 (e.g., one-to-many associations), we have to have a way to bind collections (or subsets of them) to complex widgets, such as lists. For example: a list of patients retrieved from the database.
Rendering items from a collection to a set of same widgets or page.
This requires two pages, the parent page and the child page.
The parent Page:
<data param="personList" itemize="yes"> <viewref href="views/databaseChild.zul"> <with-param name="searchPerson" param="." /> </viewref> </data>
The Inner Page:
<param name="searchPerson" adapter="demo.viewAdapters.PersonViewAdapter" /> <databinding> <textbox /> <data param="searchPerson" property="name" aspect="text" /> </databinding>
If we have to pull out details of certain individuals from the database and render the details of each individual on GUI the following declarative approach can be used.
In the parent page the data tag is using the personList param which is referencing a collection of person records. The viewref tag is used to render the inner page.
This shows how the parameters declared in the <param> tag in the child view are bound to a value, i.e., it is the <with-param> tag of the parent view (or “page” in ZK) that creates the child view using the <viewref> tag.
A <viewref> tag can be specified to modularize the UI design and build a complex interface from components. But when <viewref> is nested under the tag, it allows to bind a sequence of these child-views to data coming from a collection property. Setting the itemize attribute on the data tag to “yes” will create as many inner pages as there are elements on the “personList” and binds the “searchPerson” parameter of the inner view(specified by the name attribute of the <with-param>tag) with the person currently read from the collection (the “.” idiom to refer to the current object is borrowed from XSLT).
We can also populate listboxes and tabboxes using this approach. The basic concept remains the same, but we need to change the ZUML.
Combining data from multiple items and representing it using a single UI item
There might be a usecase where the name of a student is represented using a collection having the following structure and we have to represent the complete name i.e. first name + family name+ preferred name + nick name using a single textbox.
- First Item: Given Name
- Second Item: Family Name
- Third Item: Preferred Name
- Fourth Item: Nick Name
Karn provides Formatters which can combine all the items of a collection using user defined format and present it to an UI component. For Example:
<databinding> <textbox/> <data param="person" aspect="text"> <formatter format="%s, %s %s" adapter="adapters.personListViewAdapter"> <data property=”familyName” /> <data property="givenName"/> <data property=”nickName” </formatter> </data> </databinding>
The above example shows how the parent tag is using the child <formatter>tag to connect the collection containing the names referenced by the person variable to the text aspect of the textbox. The <formatter>tag has the following attributes
- format: It defines the format based on which the single element is created using the items of the collection. The format used is based on the printf format. For example in the above example the format “%s%s%s%s” says that we combine the four string items into one single string.
- adapter: The adapter that will be used to access the items of the collection based on the property attribute of the child tag.
The children tags are used to define what properties of the object referenced by the person variable to use for formatting.
Compositions are used to massage the data before setting them to the model object. For example, we can use compositions for designing an e-prescription system where the doctor has to type in the dose instructions and the composition takes in the short form and converts it into detailed directions. For example the doctor may type in “tid” which can be expanded to three times a day.
<databinding> <textbox/> <data param="this" aspect="text" property="direction"/> <composition compositionClass="org.regenstrief.mw.medication.TimingComposition"/> </data> </databinding>
In the above snippet we data-bind the textbox’s text aspect to the direction property of the model object represented by the this variable. The <composition> tag’s CompositionClass attribute specifies the fully qualified class name of the Composition implementation.
The tag can have multiple <composition> tags as children. This allows us to setup a chain of compositions for the data input by the user.
We provide an event handling mechanism which enables an application developer to encapsulate the business logic into small reusable modules. Upon an event occurrence control is delegated to the appropriate module.
Your browser may not support display of this image.
Implementation of Action interface, having the handleEvent method, is used to encapsulate the business logic. Implementation of the ViewController interface is used to delegate to a particular event. The ViewController interface has the getActionFor method which can be used to get a particular Action implementation and invoke the handleEvent method.
For example we can have an implementation of the Action interface, addItemAction , which contains the code which should be executed when the user adds an item to a list. So we can use addItemAction for all “adding item to list” usecases.
New widgets have been added which are implementation of certain ideas that we have.
Phantom feature lets us set the width of an input box using a predefined string. The input box width will be a perfect match for the predefined string, taking in consideration the various style attributes. We have extended the ZK textbox to provide the phantom feature. Other widgets can also use the phantom feature using the phantom component.
Xwsftext has been created by extending the ZK textbox. It provides the phantom and the stub feature. The stub feature allows the user to display a string in the text area. This string acts as a tooltip for the user . As soon as the focus comes to the textbox the default stub string disappears and the user can input text in the textbox. If the user does not input anything in the textbox the stub string reappears after focus goes from the textbox.
We have extended the ZK combobox so that it can provide proposals from a database table using hibernate. The autocompleter can be configured declaratively so that the developer will not have to write java code to connect the autocompleter to the data source. We have also added an attribute, threshold, which decides after how many character inputs do we get the proposals from the database. For example if the threshold is set to 2 then the proposals will be pulled out of the database when the number of characters input by the user is greater than or equal to 2.
In this article the Karn component package was introduced.
Please download the example demo project here.
Checkout http://aurora.regenstrief.org/karn for more information and resources.
- Please refer to the Data-binding section of Karn documentation for more details.
- Please check out http://en.wikipedia.org/wiki/Model-view-controller for introduction to MVC architecture.
- Please check out the multipage section in the Karn documentation
|Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License.|