- XML Reference Guide
- Overview
- What Is XML?
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- Table of Contents
- The Document Object Model
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- DOM and Java
- Informit Articles and Sample Chapters
- Books and e-Books
- Implementations
- DOM and JavaScript
- Using a Repeater
- Repeaters and XML
- Repeater Resources
- DOM and .NET
- Informit Articles and Sample Chapters
- Books and e-Books
- Documentation and Downloads
- DOM and C++
- DOM and C++ Resources
- DOM and Perl
- DOM and Perl Resources
- DOM and PHP
- DOM and PHP Resources
- DOM Level 3
- DOM Level 3 Core
- DOM Level 3 Load and Save
- DOM Level 3 XPath
- DOM Level 3 Validation
- Informit Articles and Sample Chapters
- Books and e-Books
- Documentation and Implementations
- The Simple API for XML (SAX)
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- SAX and Java
- Informit Articles and Sample Chapters
- Books and e-Books
- SAX and .NET
- Informit Articles and Sample Chapters
- SAX and Perl
- SAX and Perl Resources
- SAX and PHP
- SAX and PHP Resources
- Validation
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- Document Type Definitions (DTDs)
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- XML Schemas
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- RELAX NG
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- Schematron
- Official Documentation and Implementations
- Validation in Applications
- Informit Articles and Sample Chapters
- Books and e-Books
- XSL Transformations (XSLT)
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- XSLT in Java
- Java in XSLT Resources
- XSLT and RSS in .NET
- XSLT and RSS in .NET Resources
- XSL-FO
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- XPath
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- XML Base
- Informit Articles and Sample Chapters
- Official Documentation
- XHTML
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- XHTML 2.0
- Documentation
- Cascading Style Sheets
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- XUL
- XUL References
- XML Events
- XML Events Resources
- XML Data Binding
- Informit Articles and Sample Chapters
- Books and e-Books
- Specifications
- Implementations
- XML and Databases
- Informit Articles and Sample Chapters
- Books and e-Books
- Online Resources
- Official Documentation
- SQL Server and FOR XML
- Informit Articles and Sample Chapters
- Books and e-Books
- Documentation and Implementations
- Service Oriented Architecture
- Web Services
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- Creating a Perl Web Service Client
- SOAP::Lite
- Amazon Web Services
- Creating the Movable Type Plug-in
- Perl, Amazon, and Movable Type Resources
- Apache Axis2
- REST
- REST Resources
- SOAP
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- SOAP and Java
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- WSDL
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- UDDI
- UDDI Resources
- XML-RPC
- XML-RPC in PHP
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- Ajax
- Asynchronous Javascript
- Client-side XSLT
- SAJAX and PHP
- Ajax Resources
- JSON
- Ruby on Rails
- Creating Objects
- Ruby Basics: Arrays and Other Sundry Bits
- Ruby Basics: Iterators and Persistence
- Starting on the Rails
- Rails and Databases
- Rails: Ajax and Partials
- Rails Resources
- Web Services Security
- Web Services Security Resources
- SAML
- Informit Articles and Sample Chapters
- Books and e-Books
- Specification and Implementation
- XML Digital Signatures
- XML Digital Signatures Resources
- XML Key Management Services
- Resources for XML Key Management Services
- Internationalization
- Resources
- Grid Computing
- Grid Resources
- Web Services Resource Framework
- Web Services Resource Framework Resources
- WS-Addressing
- WS-Addressing Resources
- WS-Notifications
- New Languages: XML in Use
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- Google Web Toolkit
- GWT Basic Interactivity
- Google Sitemaps
- Google Sitemaps Resources
- Accessibility
- Web Accessibility
- XML Accessibility
- Accessibility Resources
- The Semantic Web
- Defining a New Ontology
- OWL: Web Ontology Language
- Semantic Web Resources
- Google Base
- Microformats
- StructuredBlogging
- Live Clipboard
- WML
- XHTML-MP
- WML Resources
- Google Web Services
- Google Web Services API
- Google Web Services Resources
- The Yahoo! Web Services Interface
- Yahoo! Web Services and PHP
- Yahoo! Web Services Resources
- eBay REST API
- WordML
- WordML Part 2: Lists
- WordML Part 3: Tables
- WordML Resources
- DocBook
- Articles
- Books and e-Books
- Official Documentation and Implementations
- XML Query
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- XForms
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- Resource Description Framework (RDF)
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- Topic Maps
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation, Implementations, and Other Resources
- Rich Site Summary (RSS)
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- Simple Sharing Extensions (SSE)
- Atom
- Podcasting
- Podcasting Resources
- Scalable Vector Graphics (SVG)
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- OPML
- OPML Resources
- Summary
- Projects
- JavaScript TimeTracker: JSON and PHP
- The Javascript Timetracker
- Refactoring to Javascript Objects
- Creating the Yahoo! Widget
- Web Mashup
- Google Maps
- Indeed Mashup
- Mashup Part 3: Putting It All Together
- Additional Resources
- Frequently Asked Questions About XML
- What's XML, and why should I use it?
- What's a well-formed document?
- What's the difference between XML and HTML?
- What's the difference between HTML and XHTML?
- Can I use XML in a browser?
- Should I use elements or attributes for my document?
- What's a namespace?
- Where can I get an XML parser?
- What's the difference between a well-formed document and a valid document?
- What's a validating parser?
- Should I use DOM or SAX for my application?
- How can I stop a SAX parser before it has parsed the entire document?
- 2005 Predictions
- 2006 Predictions
- Nick's Book Picks
In our last installment, we talked about the Google Web Toolkit, and using it to easily create sophisticated web applications using Java that ultimately gets translated to Javascript. In that entry, we gave you just the basic idea of how to create an application, and what the parts of the application ultimately do.
Now it's time to get down to business and actually build an application.
Start by creating a new
application called com.informit.client.Authors
. This application will be a simple page that lists a group of
authors and their relative comfort levels with specific technical areas. Ultimately, the application will use AJAX to
pull information from a remote server, but to keep things simple, for now we'll
create the Author objects within the application itself.
Let's start with Listing 1, the basic application:
Listing 1:
package com.informit.client; import com.google.gwt.core.client.EntryPoint; import com.google.gwt.user.client.ui.*; public class Authors implements EntryPoint { class Author { String authorName; int javaSkill; int rubySkill; int htmlSkill; } Author[] authors; public Author[] getAuthors (){ Author thisAuthor = new Author(); thisAuthor.authorName = "Nick Chase"; thisAuthor.javaSkill = 2; thisAuthor.rubySkill = 2; thisAuthor.htmlSkill = 3; Author thatAuthor = new Author(); thatAuthor.authorName = "Joe Schmoe"; thatAuthor.javaSkill = 1; thatAuthor.rubySkill = 1; thatAuthor.htmlSkill = 3; Author otherAuthor = new Author(); otherAuthor.authorName = "Frank Black"; otherAuthor.javaSkill = 1; otherAuthor.rubySkill = 3; otherAuthor.htmlSkill = 1; Author[] returnArray = {thisAuthor, thatAuthor, otherAuthor}; return returnArray; } String getAuthorAndSkillsHTML(int index){ Author thisAuthor = authors[index]; String returnStr = thisAuthor.authorName + "<ul><li>Java: " + thisAuthor.javaSkill + "</li>" + "<li>Ruby: " + thisAuthor.rubySkill + "</li>" + "<li>HTML: " + thisAuthor.htmlSkill + "</li></ul>"; return returnStr; } public void onModuleLoad() { authors = getAuthors(); for (int i = 0; i < authors.length; i++){ HTML thisAuthor = new HTML(getAuthorAndSkillsHTML(i)); RootPanel.get().add(thisAuthor); } } }
Starting at the top, this
class, com.informit.client.Authors
, must implement the EntryPoint
interface, so
we'll import it to start off with. We'll also import all of the com.google.gwt.user.client.ui
package to
simplify things, though of course in your production applications you'll want
to import only the classes you're actually using.
The next step, in this case,
is to create the data objects we're going to display. Again, ultimately we'll retrieve this data live, but for now
we'll create a simple internal class, Author
, which includes the name and three
skill levels for each one. Once we've
created the class, we can create an array of Author
objects and the
getAuthors()
method, which loads that array with arbitrary information. We're also creating the
getAuthorAndSkillsHTML()
method, which provides us an easy way to retrieve a
text version of each Author
object.
Now we can get on to the
actual application, as represented by the onModuleLoad()
method. In this case, the method is fairly
straightforward. For each Author
in the
authors
array, we create a new HTML widget that consists of the data for that
author, and then we add that widget to the page.
As generated, the HTML page
that displays all of this has a lot of extraneous information, but if you look
in the <GWT_HOME>/src/com/informit/public
folder, you'll see the
Authors.html
file, which acts as a "host" for the information. In Listing 2, I've cleared out all but the
absolutely necessary information:
Listing 2:
<html> <head> <title>Author Listing</title> <meta name='gwt:module' content='com.informit.Authors'> </head> <body> <script language="javascript" src="gwt.js"></script> <h1>Authors</h1> </body> </html>
Really,
there are only two indications in this file that we're even dealing with the
Google Web toolkit, and those are the meta
tag that identifies the actual
module, and the gwt.js
script, which is the main Google Web Toolkit script that loads
and runs the appropriate generated code.
If
we then execute the Authors-shell.cmd
script, we'll see something similar to
Figure 1:
Figure 1:
Simple enough, I suppose. We told it to display three HTML widgets, and it did so.
So we know it's working, and we can move on to something a little more interesting. Our first task will be to resolve a problem that isn't obvious unless you're something close to a Java guru.
The beauty of the Google Web Toolkit is how easy it makes interactivity, so our goal will ultimately be to create a page that performs actions like popping up a window with more information when you click on an author's name, and so on. It's this kind of thing that got me really excited about the toolkit. While it's possible to create handlers that react to actions such as clicks in Javascript, trying to track what you've clicked and react to the right object can be downright irritating.
So I was very excited at the prospect of being able to create code that looked like Listing 3:
package com.informit.client; import com.google.gwt.core.client.EntryPoint; import com.google.gwt.user.client.ui.*; import com.google.gwt.user.client.Window; public class Authors implements EntryPoint { class Author { String authorName; int javaSkill; int rubySkill; int htmlSkill; } ... String getAuthorAndSkillsHTML(int index){ Author thisAuthor = authors[index]; String returnStr = thisAuthor.authorName + "<ul><li>Java: " + thisAuthor.javaSkill + "</li>" + "<li>Ruby: " + thisAuthor.rubySkill + "</li>" + "<li>HTML: " + thisAuthor.htmlSkill + "</li></ul>"; return returnStr; } String getSkillsHTML(int index){ Author thisAuthor = authors[index]; String returnStr = "Java: " + thisAuthor.javaSkill + "<br />" + "Ruby: " + thisAuthor.rubySkill + "<br />" + "HTML: " + thisAuthor.htmlSkill; return returnStr; } public void onModuleLoad() { authors = getAuthors(); for (int i = 0; i < authors.length; i++){ Label thisAuthor = new Label(authors[i].authorName); thisAuthor.addClickListener(new ClickListener() { public void onClick(Widget sender) { Window.alert(getSkillsHTML(i)); } }); RootPanel.get().add(thisAuthor); } } }
This seems pretty simple, right? For each Author
object in the authors
array, create a
Label
with
the author's name, and then add a ClickListener
that pops open an alert message
with the skills for that author. It
looks like an easy way to generate interactive content based on what the user
clicks.
Well, unfortunately, it's a little too simple. If you refresh the Google window browser, you'll get an error that points you to the shell:
Here, I'm afraid, we've run up against the structure of Java
itself. Because the variable i
is not
final
, we can't reference it from within the ClickListener
class. And because the variable changes as we loop through
the array, we can't label it final
.
Fortunately, that doesn't mean that we're sunk. If you look at the ClickListener
object
itself, you'll see that we have easy access to the object sending the event,
which is, conveniently, the object the user has clicked:
... for (int i = 0; i < authors.length; i++){ Label thisAuthor = new Label(authors[i].authorName); thisAuthor.addClickListener(new ClickListener() { public void onClick(Widget sender) { Label clickedLabel = (Label)sender; Window.alert(clickedLabel.getText()); } }); RootPanel.get().add(thisAuthor); } ...
This enables us to grab the object, turn it back into a
Label
, and then access its text. If
we run the application, we can see the names pop up in a normal alert box, as
you can see in Figure 3:
Figure 3:
The Window
object represents the
actual browser window, just as it does in JavaScript.
OK, so let's take stock of where we are. We can loop through each of the objects and display them on the page, complete with listeners that generate content based on the object we clicked. Now we just need a way to refer that back to the object itself.
package com.informit.client; import com.google.gwt.core.client.EntryPoint; import com.google.gwt.user.client.ui.*; import com.google.gwt.user.client.Window; import java.util.ArrayList; public class Authors implements EntryPoint { class Author { String authorName; int javaSkill; int rubySkill; int htmlSkill; } Author[] authors; ArrayList authorIndexes = new ArrayList(); public Author[] getAuthors (){ Author thisAuthor = new Author(); thisAuthor.authorName = "Nick Chase"; thisAuthor.javaSkill = 2; thisAuthor.rubySkill = 2; thisAuthor.htmlSkill= 3; authorIndexes.add("Nick Chase"); Author thatAuthor = new Author(); thatAuthor.authorName = "Joe Schmoe"; thatAuthor.javaSkill = 1; thatAuthor.rubySkill = 1; thatAuthor.htmlSkill = 3; authorIndexes.add("Joe Schmoe"); Author otherAuthor = new Author(); otherAuthor.authorName = "Frank Black"; otherAuthor.javaSkill = 1; otherAuthor.rubySkill = 3; otherAuthor.htmlSkill = 1; authorIndexes.add("Frank Black"); Author[] returnArray = {thisAuthor, thatAuthor, otherAuthor}; return returnArray; } String getAuthorAndSkillsHTML(int index){ … } String getSkillsHTML(int index){ … } public void onModuleLoad() { authors = getAuthors(); for (int i = 0; i < authors.length; i++){ Label thisAuthor = new Label(authors[i].authorName); thisAuthor.addClickListener(new ClickListener() { public void onClick(Widget sender) { Label clickedLabel = (Label)sender; int index = authorIndexes.indexOf(clickedLabel.getText()); Window.alert(getSkillsHTML(index)); } }); RootPanel.get().add(thisAuthor); } } }
What we're doing here is creating an ArrayList
that
parallels the actual Array
of Author
objects. This enables us to use the
ArrayList
's indexOf()
method to locate a
specific item based on the author name, and then use that information to get
the relevant skills in the alert box. (Yes, there are more efficient ways to do this, such as an ArrayList
using generics that holds all of the information. But the point is that you can create something that links back to
the original data based on the information that you have, in this case the text
of a label.)
The result is an alert box that displays the raw HTML:
Of course, that's not terribly attractive, now is it? We'll look at some of the different UI classes the Google Web Toolkit provides in future installments, but for now let's take a quick look at converting this alert box to a popup.
If we were to do this in raw Javascript, we'd need to do all kinds of work setting up hidden divs, event handlers, figuring out positioning, and so on. Creating a popup in the GWT's Java, however, isn't nearly that complicated:
... String getSkillsHTML(int index){ Author thisAuthor = authors[index]; String returnStr = "Java: " + thisAuthor.javaSkill + "<br/>" + "Ruby: " + thisAuthor.rubySkill + "<br/>" + "HTML: " + thisAuthor.htmlSkill + ""; return returnStr; } private static class AuthorPopup extends PopupPanel { public AuthorPopup(HTML contents) { super(true); add(contents); } } public void onModuleLoad() { authors = getAuthors(); for (int i = 0; i < authors.length; i++){ Label thisAuthor = new Label(authors[i].authorName); thisAuthor.addClickListener(new ClickListener() { public void onClick(Widget sender) { Label clickedLabel = (Label)sender; int index = authorIndexes.indexOf(clickedLabel.getText()); HTML popupText = new HTML(getSkillsHTML(index)); AuthorPopup popup = new AuthorPopup(popupText); int left = sender.getAbsoluteLeft() + 70; int top = sender.getAbsoluteTop() + 10; popup.setPopupPosition(left, top); popup.setStyleName("popupStyle"); popup.show(); } }); RootPanel.get().add(thisAuthor); } } }
A popup is a HTML div that appears on the page in response
to an event, and can optionally disappear when the user clicks outside of that
div. We start by creating a subclass of
the PopupPanel
class, AuthorPopup
, and creating a constructor that enables us
to perform two tasks. The first is to
set the panel to disappear when the user clicks outside of it (using
super(true)
, since this is an attribute of the parent PopupPanel
class) and the
second is to set the contents to an HTML widget.
Once we've created the class, we can use it to create a new
popup when the user clicks one of the author names. To do that, we first define the contents, and then use them to
create the new AuthorPopup
object. From
there, we set the position of the popup relative to the name the user clicked,
set the CSS style (which we'll see in a moment) and show the actual popup. (Remember, this code only gets executed when
the user clicks a name, so it's appropriate to show it right away.)
The style determines what the popup actually looks
like. Using CSS, you can add background
images, font styles, and all sorts of decorative elements. I'm more technical than visual, however, so
we'll stick to the simple things. Define the CSS class in the Authors.html
file, just as you would do with
any other CSS styles:
<html> <head> <title>Author Listing</title> <meta name='gwt:module' content='com.informit.Authors'> <style type="text/css"> .popupStyle { background-color: white; border: 1px solid red; padding: 10px; } </style> </head> <body> <script language="javascript" src="gwt.js"></script> <h1>Authors</h1> </body> </html>
The result is a simple div that appears when you click on one of the author names.
Now that we've got the basics of creating interactive interfaces down, we can look at GWT's other capabilities.