SmartBindings
Javeline Platform uses has a strict seperation between model, view and controller. The so-called MVC pattern. The Model is represented by a j:model tag. The Controller the Javeline component (i.e. j:List). The View is the SmartBinding configured by a j:smartbinding tag and others.
The advantages of having a clear seperation are numerous and are out of scope for this article. Suffice to say that by seperating these layers your application will be easier to manage and the possibilities of reuse are far greater.
bindings
In this example I want to create a List which is filled using arbitrary xml from a file (users.xml). The xml looks like this:
<users> <user name="Ruben" id="1" type="admin" /> <user name="Arnold" id="2"/> <user name="Henrik" id="3"/> <user name="Morgan" id="4"/> <user name="Rik" id="5"/> </users>
The following JML code will do exactly what we want:
<j:model id="mdlUsers" file="users.xml"/>
<j:smartbinding id="sbUsers">
<j:bindings>
<j:caption select="@name" />
<j:icon default="icoUsers.gif" />
<j:traverse select="user" />
</j:bindings>
</j:smartbinding>
<j:List model="mdlUsers" smartbinding="sbUsers" />
<j:Button onclick="ActionTracker.undo()">Undo</j:Button>
<j:Button onclick="ActionTracker.redo()">Redo</j:Button>
The model called mdlUsers loads the file users.xml. The list connects to this model and loads the data. The smartbinding sbUsers determines the view on the data. The bindings section is one of three of the smartbinding. This binding tag contains three rules. The Traverse rules determines the nodes which are rendered in the list using the Xpath statement. The Caption rule determines the caption of each node. The icon is the same for each node and is therefore given a default attribute. This smartbinding will select all user tags and retrieve for each of them the caption from the name attribute, always setting the icon to icoUsers.gif.
I always like to work as efficient as possible and a shorter syntax helps. The example below does exactly the same as the one above.
<j:List model="file:users.xml">
<j:bindings>
<j:caption select="@name" />
<j:icon default="icoUsers.gif" />
<j:traverse select="user" />
</j:bindings>
<j:List>
There are many different transformation rules available. You can specify a mask, use XSLT, JSLT or javascript methods to process the data from XML. Check out he SmartBindings cheatsheet for more information.
Undo & Redo
One of the advantages of using a strict and good seperation between these MVC layers is the ‘free’ undo/redo feature. Each action of the component can be undone by calling ActionTracker.undo(). The undo stack has no limit. In the example above, press the undo/redo buttons after you have removed/renamed some nodes to see the ‘magic’.
actions
Lets say that we have a web service from which we load the users. When we rename a user in the list the data in the model is changed automatically. The data on the server however is not. This is where the actions come in. Each component has specific actions associated with it. Lets take a look at the following example:
<j:list model="file:users.xml">
<j:bindings>
<caption select="@name" />
<icon default="icoUsers.gif" />
<traverse select="user" />
</j:bindings>
<j:actions>
<j:rename
select="self::user"
set="rpc:comm;renameUser(xpath:@id;xpath:@name)" />
<j:remove
select="self::user[not(@admin)]"
set="eval:alert(xmlNode)" />
</j:actions>
<j:list>
The two action rules specify that any user can be renamed and all users removed except the ones with the admin attribute set. When a user is allowed to rename or remove a node the action is executed. In the case of rename an RPC method is called with xpath based arguments. When a node is removed the javascript expression is evaluated which could handle the synchronization of the data.