In this article I show you how to control the backbutton in your Javeline PlatForm application. I’ll take you step by step through creating a breadcrumb navigation for a typical product database site. It uses 4 states (similar to pages in static websites). The key to this implementation is that all state information is encoded in the hash. All information is stored in the url using the hash (http://example.com#information). This makes navigating your ajax site as intuitive as any website:
| State | Description |
|---|---|
| Home | The state where the application starts and can return to start searching |
| Search | The state where the search results are displayed |
| Product | The state where the product presentation is displayed |
Why use state objects?
An alternative to using state objects is to define the state in a j:pages object (similar to a tab component but without the buttons). This would allow you to group the components you need in different pages. One page can be showed at a time, showing the underlying components. This limits you significantly in reusing components on different ‘pages’ (states). In the example below, we’ll be creating a ‘trNav’ object that is used both on the home state and the search state, but not the product state. As you can see this allows for a much higher granularity in control and reuse.
Setting up the basic JML
We’ll first set up some components. There will be 3 states represented in the application. In a real application you’d might want to use a completely different way of setting up your UI, but the principle will be the same.
//Create some Javeline Components using some markup <j:text id="txtBreadcrumb" height="40" width="300"/> <j:tree id="trNav" height="100"/> <j:bar id="barHome"> <h3>Home</h3> </j:bar> <j:bar id="barSearch"> <h3>Search</h3> <j:textbox id="inKeyword" value="my_product" /> </j:bar> <j:bar id="lstProduct"><h3>Product</h3></j:bar>
By setting up 3 state objects we can specify which objects are displayed during which state:
<j:state id="stHome" trNav.visible="true" barHome.visible="true" barSearch.visible="false" lstProduct.visible="false" active="true" /> <j:state id="stSearch" trNav.visible="true" barHome.visible="false" barSearch.visible="true" lstProduct.visible="false" /> <j:state id="stProduct" trNav.visible="false" barHome.visible="false" barSearch.visible="false" lstProduct.visible="true" />
Creating the breadcrumb javascript
As you can see we haven’t specified the txtBreadcrumb component, it will therefore be visible throughout the existence of the application. The home state is set to active. This activates the home state right after the application started. Because the breadcrumb navigation is always implementation specific, we’ll write a small javascript object to handle things for us:
CrumbNav = {
last : [],
exec : function(type, id){
switch(type){
case "home":
stHome.activate();
break;
case "search":
return doSearch(id || inKeyword.getValue());
break;
case "product":
stProduct.activate();
break;
}
CrumbNav.set(type);
},
add : function(type, id){
//Creates a link tag in HTML
return '<a href="javascript:void(0)" onclick="CrumbNav.exec('" + type + "', '' + id + '')">" + type.uCaseFirst() + "</a>';
},
set : function(type, id){
var str = [this.add('home')];
if(type == "home"){
this.last = [];
//Join the elements of the array creating a string of all the link tags and passes it to the txtBreadcrumb component.
txtBreadcrumb.setValue(str.join(" > "));
return;
}
if(type != "search" && this.last.length)
str.push(this.add(this.last[0], this.last[1]));
str.push(this.add(type, id));
this.last = [type, id];
//Join the elements of the array creating a string of all the link tags and passes it to the txtBreadcrumb component.
txtBreadcrumb.setValue(str.join(" > "));
}
}
function doSearch(id){
//handle searching here
CrumbNav.set("search", id);
stSearch.activate();
inKeyword.setValue(id);
}
We’ll add some action to our application by adding 3 buttons that switch to a state:
<j:button caption="Home" onclick="CrumbNav.exec('home');" />
<j:button caption="Search" onclick="CrumbNav.exec('search');" />
<j:button caption="Product" onclick="CrumbNav.exec('product');" />
If you run the application again you will find yourself in control of the states of the application. You will also see the breadcrumb navigation being created as you press the buttons, one after the other.
The History object
We still need to implement back button support. We will record the state in the hash. The state consists of both the active state and an id containing information about the search or the product that is loaded. To do this we’ll add the following line to the set function.
jpf.History.addPoint(type + "|" + (id || ""));
Now just add the onchange event to handle page navigation:
jpf.History.onchange = function(page){
var data = page.split("|");
CrumbNav.exec(data[0], data[1]);
}
If you now click around the application you will see the backbutton lighting up. You can use it to change the state and to go back whenever you want, and forward to get your state back. Now it’s working all fine, and almost exactly like old-skool non-ajax sites work. But there’s one last thing to do, and that is being able to copy&paste url’s from the title bar to others. Add the following code at the end to set the state at the start of the application. You’ll need to to remove active=”true” from the stHome element for this to work.
var state = location.href.match(/#(.*)$/) ? RegExp.$1 : "home"; jpf.History.init(state);
Conclusion
In this article we have created a native website navigation in an Ajax application using Javeline PlatForm. Although not build for IE8, this solution closely resembles IE8’s way of handling hash changes (with the onhashchange event). When IE8 stops crashing my pc I will make it work natively for IE8. This solution has been tested in Safari 3, Firefox and IE6+.
This works from v0.98.2 which can be downloaded from http://developer.javeline.net/downloads.php. You can find the sample code here.
