Enrich Grails Server Pages (GSPs) with ZK
Hawk Chen, Engineer, Potix Corporation
January 16, 2012
ZK 5
Introduction
When developing a web application with AJAX, we tend to combine multiple related functions into one page instead of separating them into different pages. On the other hand, when developing with JSP/GSP, page-based design style is usually adopted because submitting a request will send all the data on the page to the server and response will reload the whole page. Hence, there can’t be too much information on one page otherwise the application response time will increase.
However, when AJAX comes into play, the design style changes because AJAX helps developers to send and receive less data for each user interaction, which means that more functions can be added to one page with more UI controls. This way, users can trigger different functions by different UI controls without the need to wait for the whole page to reload. The major benefit of this is that it makes a web application more like a desktop application.
Our example application “RaceTrack” has 3 GSPs and each of them provides a different function. Our goal is to combine all the functions into one page.
Preparation
list.gsp provides search and deletion in an AJAX way, but to create and/or edit a race, users are still required to wait for the reloading of another page. These two functions do not benefit from AJAX. Now, we are going to present how users can combine the 3 GSPs into one using AJAX.
As list.gsp contains more functions than others, we decided to use it as the base to build the combined page on it. We plan to combine all functions into fusion.gsp.
Duplicate list.gsp and rename it to fusion.gsp.
Modify <z:window> attribute “apply” as following:
<z:window apply="racetrack.race.FusionComposer"/>
Create the corresponding composer
- Duplicate ListComposer.groovy and rename it to FusionComposer.groovy.
- Open FusionComposer.groovy and change class name to FusionComposer.
This means that we assign Fusion Composer
to handle all events from <z:window>
and its child components.
Combine the Functions
Add an Action in RaceController.groovy
def fusion = {
def raceInstance = new Race()
raceInstance.properties = params
return [raceInstance: raceInstance]
}
Combine Creation
To enable creation feature, we design a form in a similar manner to the form in create.gsp for user input.
- Copy all ZK components inside
<z:window>
(excluding window itself) in create.gsp and paste after<z:paging>
in fusion.gsp. - Change button id from “saveButton” to “createButton” and remove “Race List” button.
- Copy variable “Window self” from CreateComposer.groovy to FusionComposer.groovy.
- Copy method
“onClick_saveButton”
from CreateComposer.groovy to FusionComposer.groovy.- Rename it to
“onClick_createButton”
- Remove
redirect( )
method calling
- Rename it to
- Add
redraw()
at bottom ofonClick_createButton()
Now the “Create” button works as expected. However, after creating a race, the original data in the text remains. This may bother users as they will need to manually delete the texts. Therefore, we add a method to automatically clear the data in the textbox in which it will be called after creation.
Clear Input
To clear input fields, we need the help of component auto-wiring. To enable this feature, add the “id” attribute to each input component and declare the variable names as same type as input fields.
Textbox nameBox
Combobox citySelect
Intbox distanceBox
Intbox costBox
Datebox startDateBox
We can clear user input by manipulating these components’ values.
void clearInput(){
nameBox.value = null
citySelect.selectedItem = null
distanceBox.value = null
costBox.value = null
startDateBox.value = null
}
Call this method inside onClick_createButton()
after redraw()
.
Combine Update
Add an update button next to the create button and a variable “Button updateButton”
in FusionComposer.groovy
To avoid confusing users with 2 buttons, we make the update button invisible by setting the attribute visible to false.
<z:button id="updateButton"
label="${message(code: 'default.button.create.update', default: 'Update')}" visible="false"/>
- When updating a race, it needs “id” and “version”, we add two fields from edit.gsp
- Copy 2 Longboxes with name “id” and “version to fusion.gsp and set attribute “id” as follows:
<z:longbox id="idBox" name="id" value="${raceInstance.id}" visible="false"/>
<z:longbox id="versionBox" name="version" value="${raceInstance.version}" visible="false"/>
You can put 2 Longboxes anywhere inside <z:window>
, and we recommend to put them before <z:grid>
. Declare 2 variables in FusionComposer.groovy for them.
Longbox idBox
Longbox versionBox
The design pattern is as follows: when users click the edit button in any row, the update button appears, the create button becomes invisible, and transfer selected row’s data into each input field. So, we have to do these actions inside the “onClick” event handler for edit button.
Modify the code about toolbar button creation inside rowRenderer closure as follows:
onClick:{
idBox.value = raceInstance.id
versionBox.value = raceInstance.version
nameBox.value = raceInstance.name
citySelect.selectedItem = citySelect.items.find { it.value == raceInstance.city }
distanceBox.value = raceInstance.distance
costBox.value = raceInstance.cost
startDateBox.value = raceInstance.startDate
updateButton.visible = true
createButton.visible = false
})
We remove href attribute and add onClick attribute with a closure.
To make update button work, we create an event handler based on onClick_saveButton()
in EditComposer.groovy
- Copy
void onClick_saveButton(Event e)
inEditComposer.groovy
toFusionComposer.groovy
- Rename the method to
void onClick_updateButton(Event e)
- Remove all
redirect()
- Call
redraw()
andclearInput()
at the end of the method likeonClick_createButton()
After the update, switch back to creation function, so make update button invisible and create button visible.
The final result of onClick_updateButton(Event e)
will be as follows:
void onClick_updateButton(Event e) {
...
redraw()
clearInput()
updateButton.visible = false
createButton.visible = true
}
The update function is now completed.
Live Demo
ZK Enrich Your Pages
One of the most criticized points of page based web application design is the bad user experience it brings about. People are tired of long response times and also having to find desired functions by switching in between pages. Consequently, embedding more functions into one page makes your web application more powerful, convenient and competitive to desktop applications. With this as the ultimate goal, ZK is the best way to enrich your application.
Resources
- View the source code
- Download the WAR file
Comments
Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License. |