Enrich Grails Server Pages (GSPs) with ZK"

From Documentation
m (corrected date from 2011 to 2012)
(5 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 
{{Template:Smalltalk_Author|
 
{{Template:Smalltalk_Author|
 
|author=Hawk Chen, Engineer, Potix Corporation
 
|author=Hawk Chen, Engineer, Potix Corporation
|date=January 16, 2011
+
|date=January 16, 2012
 
|version=ZK 5
 
|version=ZK 5
 
}}
 
}}
Line 11: Line 11:
 
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.
 
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.
+
Our example application [http://books.zkoss.org/wiki/Small_Talks/2012/January/Ajax_GSP_with_ZK “RaceTrack”] has 3 GSPs and each of them provides a different function. Our goal is to combine all the functions into one page.
  
 
=Preparation=
 
=Preparation=
Line 23: Line 23:
 
Modify '''<z:window>''' attribute “apply” as following:
 
Modify '''<z:window>''' attribute “apply” as following:
  
<source lang="java">
+
<source lang="xml">
   apply=”racetrack.race.FusionComposer”
+
   <z:window apply="racetrack.race.FusionComposer"/>
 
</source>
 
</source>
  
Line 65: Line 65:
 
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.
 
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.
  
:<tt>Textbox nameBox</tt>
+
<source lang="groovy">
:<tt>Combobox citySelect</tt>
+
Textbox nameBox
:<tt>Intbox distanceBox</tt>
+
Combobox citySelect
:<tt>Intbox costBox</tt>
+
Intbox distanceBox
:<tt>Datebox startDateBox</tt>
+
Intbox costBox
 +
Datebox startDateBox
 +
 
 +
</source>
  
 
We can clear user input by manipulating these components’ values.
 
We can clear user input by manipulating these components’ values.
  
<source lang="java">
+
<source lang="groovy">
 
void clearInput(){
 
void clearInput(){
 
nameBox.value = null
 
nameBox.value = null
Line 90: Line 93:
 
To avoid confusing users with 2 buttons, we make the update button invisible by setting the attribute visible to false.
 
To avoid confusing users with 2 buttons, we make the update button invisible by setting the attribute visible to false.
  
<source lang="java">
+
<source lang="xml">
 
<z:button id="updateButton"
 
<z:button id="updateButton"
 
label="${message(code: 'default.button.create.update', default: 'Update')}" visible="false"/>
 
label="${message(code: 'default.button.create.update', default: 'Update')}" visible="false"/>
Line 98: Line 101:
 
:Copy 2 Longboxes with name “id” and “version to fusion.gsp and set attribute “id” as follows:
 
:Copy 2 Longboxes with name “id” and “version to fusion.gsp and set attribute “id” as follows:
  
<source lang="java">
+
<source lang="xml">
 
<z:longbox id="idBox" name="id" value="${raceInstance.id}" visible="false"/>
 
<z:longbox id="idBox" name="id" value="${raceInstance.id}" visible="false"/>
 
<z:longbox id="versionBox" name="version" value="${raceInstance.version}" visible="false"/>
 
<z:longbox id="versionBox" name="version" value="${raceInstance.version}" visible="false"/>
Line 105: Line 108:
 
You can put 2 Longboxes anywhere inside <tt><z:window></tt>, and we recommend to put them before <tt><z:grid></tt>. Declare 2 variables in ''FusionComposer.groovy'' for them.
 
You can put 2 Longboxes anywhere inside <tt><z:window></tt>, and we recommend to put them before <tt><z:grid></tt>. Declare 2 variables in ''FusionComposer.groovy'' for them.
  
:<tt>Longbox idBox</tt>
+
<source lang="groovy">
:<tt>Longbox versionBox</tt>
+
Longbox idBox
 +
Longbox versionBox
 +
 
 +
</source>
  
 
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.
 
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.
Line 112: Line 118:
 
Modify the code about toolbar button creation inside rowRenderer closure as follows:
 
Modify the code about toolbar button creation inside rowRenderer closure as follows:
  
<source lang="java">
+
<source lang="groovy">
 
onClick:{
 
onClick:{
 
idBox.value = raceInstance.id
 
idBox.value = raceInstance.id
Line 139: Line 145:
 
The final result of <tt>onClick_updateButton(Event e)</tt> will be as follows:
 
The final result of <tt>onClick_updateButton(Event e)</tt> will be as follows:
  
<source lang="java">
+
<source lang="groovy">
 
void onClick_updateButton(Event e) {
 
void onClick_updateButton(Event e) {
 
...
 
...

Revision as of 00:13, 15 May 2012

DocumentationSmall Talks2012JanuaryEnrich Grails Server Pages (GSPs) with ZK
Enrich Grails Server Pages (GSPs) with ZK

Author
Hawk Chen, Engineer, Potix Corporation
Date
January 16, 2012
Version
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.

  1. Copy all ZK components inside <z:window> (excluding window itself) in create.gsp and paste after <z:paging> in fusion.gsp.
  2. Change button id from “saveButton” to “createButton” and remove “Race List” button.
  3. Copy variable “Window self” from CreateComposer.groovy to FusionComposer.groovy.
  4. Copy method “onClick_saveButton” from CreateComposer.groovy to FusionComposer.groovy.
    Rename it to “onClick_createButton”
    Remove redirect( ) method calling
  5. Add redraw() at bottom of onClick_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.

Enrich Grails Server Pages with ZK 01.png

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

  1. Copy void onClick_saveButton(Event e) in EditComposer.groovy to FusionComposer.groovy
  2. Rename the method to void onClick_updateButton(Event e)
  3. Remove all redirect()
  4. Call redraw() and clearInput() at the end of the method like onClick_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.

Enrich Grails Server Pages with ZK 02.png

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


Comments



Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License.