Enrich Grails Server Pages (GSPs) with ZK"

From Documentation
m (correct highlight (via JWB))
 
(4 intermediate revisions by 3 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 32: Line 32:
 
*Open FusionComposer.groovy and change class name to FusionComposer.
 
*Open FusionComposer.groovy and change class name to FusionComposer.
  
This means that we assign <tt>Fusion Composer</tt> to handle all events from <tt><z:window></tt> and its child components.
+
This means that we assign <code>Fusion Composer</code> to handle all events from <code><z:window></code> and its child components.
  
 
=Combine the Functions=
 
=Combine the Functions=
Line 50: Line 50:
 
To enable creation feature, we design a form in a similar manner to the form in '''create.gsp''' for user input.  
 
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 <tt><z:window></tt> (excluding window itself) in create.gsp and paste after <tt><z:paging></tt> in  fusion.gsp.
+
#Copy all ZK components inside <code><z:window></code> (excluding window itself) in create.gsp and paste after <code><z:paging></code> in  fusion.gsp.
 
#Change button id from ''“saveButton”'' to ''“createButton”'' and remove ''“Race List”'' button.
 
#Change button id from ''“saveButton”'' to ''“createButton”'' and remove ''“Race List”'' button.
 
#Copy variable ''“Window self”'' from ''CreateComposer.groovy'' to ''FusionComposer.groovy''.
 
#Copy variable ''“Window self”'' from ''CreateComposer.groovy'' to ''FusionComposer.groovy''.
#Copy method <tt>“onClick_saveButton”</tt> from ''CreateComposer.groovy'' to ''FusionComposer.groovy.''
+
#Copy method <code>“onClick_saveButton”</code> from ''CreateComposer.groovy'' to ''FusionComposer.groovy.''
#:Rename it to <tt>“onClick_createButton”</tt>
+
#:Rename it to <code>“onClick_createButton”</code>
#:Remove <tt>redirect( )</tt> method calling
+
#:Remove <code>redirect( )</code> method calling
#Add <tt>redraw()</tt> at bottom of <tt>onClick_createButton()</tt>
+
#Add <code>redraw()</code> at bottom of <code>onClick_createButton()</code>
  
 
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.
 
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.
Line 86: Line 86:
 
</source>
 
</source>
  
Call this method inside <tt>onClick_createButton()</tt> after <tt>redraw()</tt>.
+
Call this method inside <code>onClick_createButton()</code> after <code>redraw()</code>.
  
 
==''Combine Update''==
 
==''Combine Update''==
  
Add an update button next to the create button and a variable <tt>“Button updateButton”</tt> in ''FusionComposer.groovy''
+
Add an update button next to the create button and a variable <code>“Button updateButton”</code> in ''FusionComposer.groovy''
 
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.
  
Line 106: Line 106:
 
</source>
 
</source>
  
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 <code><z:window></code>, and we recommend to put them before <code><z:grid></code>. Declare 2 variables in ''FusionComposer.groovy'' for them.
  
 
<source lang="groovy">
 
<source lang="groovy">
Line 134: Line 134:
 
We remove href attribute and add onClick attribute with a closure.
 
We remove href attribute and add onClick attribute with a closure.
  
To make update button work, we create an event handler based on <tt>onClick_saveButton()</tt> in <tt>EditComposer.groovy</tt>
+
To make update button work, we create an event handler based on <code>onClick_saveButton()</code> in <code>EditComposer.groovy</code>
  
#Copy <tt>void onClick_saveButton(Event e)</tt> in <tt>EditComposer.groovy</tt> to <tt>FusionComposer.groovy</tt>
+
#Copy <code>void onClick_saveButton(Event e)</code> in <code>EditComposer.groovy</code> to <code>FusionComposer.groovy</code>
#Rename the method to <tt>void onClick_updateButton(Event e)</tt>
+
#Rename the method to <code>void onClick_updateButton(Event e)</code>
#Remove all <tt>redirect()</tt>
+
#Remove all <code>redirect()</code>
#Call <tt>redraw()</tt> and <tt>clearInput()</tt> at the end of the method like <tt>onClick_createButton()</tt>
+
#Call <code>redraw()</code> and <code>clearInput()</code> at the end of the method like <code>onClick_createButton()</code>
  
 
After the update, switch back to creation function, so make update button invisible and create button visible.
 
After the update, switch back to creation function, so make update button invisible and create button visible.
  
The final result of <tt>onClick_updateButton(Event e)</tt> will be as follows:
+
The final result of <code>onClick_updateButton(Event e)</code> will be as follows:
  
 
<source lang="groovy">
 
<source lang="groovy">

Latest revision as of 04:19, 20 January 2022

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.