A quick introduction to using GQuery

Introduction

GQuery, or GwtQuery, is a jQuery-like library for GWT that enables a page-oriented progressive enhancement style programming model. For more information, please watch the Google I/O Session or read the Riviera-Dev Presentation.

Setting up a project

Maven Archetype

The easiest way to setup a gquery project from scratch is to create a new one using maven and the gquery-archetype, there is a [page](Insert url here) describing the procedure.

Maven Setup

If you want to add GQuery on an existing maven project or you don't want to use the maven archetype, you have simply to add the following lines in your pom.xml file :

<dependencies>
   <dependency>
     <groupId>com.googlecode.gwtquery</groupId>
     <artifactId>gwtquery</artifactId>
     <!-- Check last available version in the downloads page -->
     <version>x.x.x</version>
     <!-- If you are using old versions of gwt, uncomment the appropriate line -->
     <!-- <classifier>2.1.0</classifier> -->
     <!-- <classifier>2.0.1</classifier> -->
     <scope>provided</scope>
   </dependency>
 </dependencies>

If you want to use the snapshot version of GQuery check the Download page for more information.

Manually

You could be interested in setting up your project by hand if you don't want to use maven, or it is an already created project.

  • First you'll need to download the latest stable version of the gwtquery library related to your GWT version and place it in your classpath.
  • If you're an experienced GWT user, you probably already know how to do this, but if you're a beginner, here's a quick refresher.

First, create a new project by running

$GWT_HOME/webAppCreator gwtquery.sample.Sample

which will create a bunch of files containing a sample project. Find the build.xml file and edit the section with id="project.class.path" adding

<pathelement location="PATH_TO_DOWNLOADED_gwtquery-1.0-SNAPSHOT.jar"/>
  • If you're using Eclipse, you may also want to edit the .classpath file and add the following:
<classpathentry kind="lib" path="PATH_TO_DOWNLOADED_gwtquery-1.0-SNAPSHOT.jar"/>
  • Next, edit the src/gwtquery/sample/Sample.gwt.xml file or your project's existing module file, and add the following line to import GQuery into your GWT module:
<inherits name='com.google.gwt.query.Query'/>
  • Finally, in your module entry point class (e.g. src/gwtquery/sample/client/Sample.java) add the following import statements to make GQuery easy to use:
import com.google.gwt.query.client.GQuery;
import com.google.gwt.query.client.Function;
import com.google.gwt.query.client.Selector;
import com.google.gwt.query.client.Selectors;
import static com.google.gwt.query.client.GQuery.*;
import static com.google.gwt.query.client.css.CSS.*;

Using GQuery

There are a wealth of detailed jQuery Tutorials that teach the basic concepts, most of which work in GQuery. What follows is a condensed, simplified version. To use GQuery, you first design your HTML page to contain the desired static or dynamic content (e.g. generated by JSP). Once you have what you want, you insert a script tag to load up your GQuery module, for example in war/Sample.html you can add the following:

<script type="text/javascript" language="javascript" src="sample/sample.nocache.js"></script>

This causes the compiled Javascript for the GQuery module to be run when the page is loaded. Next, you start attaching behavior to the HTML content in your host page by using CSS selectors. For the purposes of writing a simple example, load up src/gwtquery/sample/client/Sample.java and delete the entire body of the onModuleLoad() function.

We are now ready to write our first bit of GQuery code.

Selecting Content

The first core principle of GQuery is using CSS Selectors to find DOM nodes quickly and efficiently. The Sample.html file contains an H1 tag, let's select it by writing the following code in the onModuleLoad() function:

$("h1");

This code performs the equivalent of document.getElementsByTagName("h1") and stores the resulting matches in a GQuery object for future manipulation. The $ static function is an all purpose catch all function that is actually GQuery.$. It takes as arguments either a CSS Selector, an HTML string, an Element, a Widget, a collection of Element or Widget, or a NodeList and stores them for manipulation as the matched set.

More elaborate selector examples :

//select an element having id equals to 'container'
GQuery myElement = $("#container");
//select all elements having 'article' as css class
GQuery allArticles = $(".article");
/select all cells of tables
GQuery allCells = $("table > tr > td");
//find the ul elements being inside a element with class 'article' itself inside a element with id 'container'
GQuery articleUls = $("#container .article ul");

Compile Time Selectors

If you've mostly identified the CSS selectors you'll be using, you may convert runtime selectors into compile-time selectors. The difference is, they have the potential to run a lot faster, produce smaller code, and detect errors sooner (at compile time).

Switching to compile time selectors is easy, first declare an interface:

interface MySelectors extends Selectors {

}

Next, for each selector, you create a method that returns a GQuery object

interface MySelectors extends Selectors {
   GQuery getAllHeaderElements();
}

then, you use an @Selector annotation to tell GWT which selector to use to evaluate that function

interface MySelectors extends Selectors {
   @Selector("h1")
   GQuery getAllHeaderElements();
}

and finally, you use GWT.create to create and invoke the function

MySelectors s = GWT.create(MySelectors.class);
GQuery allH1 = s.getAllHeaderElements();
allH1.css(CSS.BACKGROUND_COLOR.with(RGBColor.RED))

The more elaborate selector seen in the previous paragraph can be rewritten like this :

interface MySelectors extends Selectors {

   @Selector("#myId")
   GQuery getMyElement();

   @Selector(".article")
   GQuery getAllArticles();

   @Selector("table > tr > td")
   GQuery getAllCells();

   @Selector("container .article ul")
   GQuery getArticleUls();
}

Manipulating the DOM

Now that you've got some elements matched, you can start to unlock GQuery's full power by manipulating them.

Examples :

//This code changes the inner text of every matched element to "GQuery Rocks!".
$("h1").text("GQuery Rocks!");

//This code will insert `<b>Powered by GQuery</b>` into each h1 element.
$("h1").append("<b>Powered by GQuery</b>");

//hide all span with class 'hidden'
$("span.hidden").hide();

Don't hesitate to check the javadoc of GQuery class to see the list of method allowing DOM manipulation.

... and CSS easily

GQuery offers a nice, easy, IDE-friendly (i.e. allows your IDE to suggest correct values for selected property) and type-safe mechanism to change some CSS properties of the elements:

$("h1").css(CSS.BACKGROUND_COLOR.with(RGBColor.RED));

This code loops over every element in the matched set and sets the CSS background-color to red.

One area where GQuery differs from JQuery is that it offers a type-safe interface for manipulating CSS. The CSS class contains oodles of static variables for setting CSS properties, as an example, you may write:

$("h1").css(CSS.VERTICAL_ALIGN.with(VerticalAlign.TOP));

instead of

$("h1").css("vertical-align", "top");

There is now no chance that you could mistype the CSS property names and values.

Other examples:

//set the width and the overflow properties in one pass
$(".scrollable").css(CSS.WIDTH.with(Length.em(50)), CSS.OVERFLOW.with(Overflow.SCROLL));

//set the border shorthand property
$("#myId").css(CSS.BORDER.with(Length.px(2), BorderStyle.SOLID, RGBColor.BLACK));

Read the css guide for more info.

Methods chaining

Almost every method invocation in GQuery returns the same matched set, which means you can use Method Chaining to tersely apply multiple operations:

$("h1").css(CSS.BACKGROUND_COLOR.with(RGBColor.RED)).attr("align", "left").text("GQuery Rocks!");

This code simultaneously sets the CSS background-color to red, sets the ALIGN attribute to LEFT, and changes the inner text of every matched element to "GQuery Rocks!".

Binding Events

Add an event handler

To do anything useful, you're going to want to bind event handling to any DOM elements. You do this by using an event specific function and passing it a callback. Let's change the previous code so that the background color doesn't change until you click on the element.

$("h1").click(new Function() {
  public boolean f(Event e) {
    $(e).css(BACKGROUND_COLOR, RED);
    return true;
  }
});

The interface Function is a multi-purpose callback interface used for event handlers and iteration functions in GQuery. For event handlers, we override the f(Event e) function which is called when the event is triggered. You then use the $ function to convert the event object into a GQuery object which wraps the element on which the event occurred. In this case, the source of the event has its background turned red.

In many cases, the callback code is so simple, it doesn't need a full anonymous inner class. In this case, you may use the Lazy GQuery interface to defer execution of GQuery methods and turn them into callbacks.

$("h1").click(lazy().css(BACKGROUND_COLOR, RED).done());

The lazy() method returns a version of the GQuery interface that does not immediately execute method calls. Instead, it queues up method calls until done() is invoked, and turns them into an instance of the Function callback interface.

In the example above, we use the click(Function...) method in order to bind a handler on the click event. In fact, GQuery provides shortcut methods for binding the standard event types . So you will find for example blur(Function...) mousemove(Function...) keyup(Function...) and so on. In a more general way, you can use the bind() to bind the same handler on the many events :

import com.google.gwt.user.client.Event;
...

//bind the same handler for mouseout and mouse over events
$("h1").bind(Event.ONMOUSEOVER | Event.ONMOUSEOUT, new Function() {
  public boolean f(Event e) {
    $(e).toggleClass("highlight");
    return true;
  }
});

Remove an event handler

Any handler that has been attached with bind() or any shorcut method (click(), dblclick()...) can be removed with the help of the unbind() method.

$("h1").unbind(Event.ONCLICK);

live() and let die()

The bind() allows to bind event handling on existing element. But it would be nice if we can attach same handler on existing element and on future element. That's the purpose of the live() method : Attach a handler to the event for all elements which match a selector, now and in the future.

$("h1").live(Event.ONCLICK, new Function() {
  public boolean f(Event e) {
    $(e).css(BACKGROUND_COLOR, RED);
    return true;
  }
});

This code binds click handler to all existing h1 element of the document and all h1 that will be added in the future.

$("body").append("<h1>I'm also clickable</h1>");

When the user will click on this new h1, its background will be set to red.

If you specify a context for your GQuery object, the live handlers are called only when the element receiving the event is a descendant of the context element and matching the selector :

Element mainDiv = $("#mainDiv").get(0);

$("h1", mainDiv).live(Event.ONCLICK, new Function() {
  public boolean f(Event e) {
    $(e).css(BACKGROUND_COLOR, RED);
    return true;
  }
});

Only h1 elements inside the element with id mainDiv are (or will be) clickable.

In the same way that unbind() allows to remove handler attached by the bind() method, the die() method allow to remove live handler. In order for this method to function correctly, the selector used with the die() method must match exactly the selector initially used with the live() method.

Animating the DOM

QQuery offers some methods to create animation on DOM elements by changing their css property.

The animate() method

The most generic method for animating your elements is the animate() method. It allows you to create animation effects on any numeric or color CSS property.

Let's take examples :

$("#foo").animate("left:'500px'", 2000);

When it is executed, this code will move the element from its original position to 500px to the left and the animation will take 2 seconds.

If a value is supplied with a leading += or -= sequence of characters, then the target value is computed by adding or subtracting the given number from the current value of the property.

$("#foo").animate("width:'+=500'", 1000);

The width of the element with id foo will be increase of 500px.

A callback function can be passed to the animate() method. This callback will be called at the end of the animation

$("#foo").animate("width:'+=500'", 1000, new Function(){
    public void f(Element e){
        $(e).css(CSS.BACKGROUND_COLOR.with(RGBColor.RED);
    }
});

The width of the element with id foo will be increase of 500px and once the animation is finished, its background color will be turned to red.

All examples saw until now concerned css numeric properties, but all css color properties (color, backgroundColor, borderColor...) can be also animated by the animate method. Just pass the desired color in either hexadecimal or rgb or literal format :

$("#foo").animate("color:'red', backgroundColor:'rgb(0, 128, 0)', borderColor:'#0000ff'");

During the animation, the text color will change to red, the background color to green and the border color to blue.

The last example shows that you are able to animate many css properties in the same animation. But is it possible to animate first the text color and after the background color ?? Sure you can. The animate() method is based on a queue system. Thats means that all call to animate() method will be placed in a queue in waiting that the animation currently running finishes before to execute itself.

$("#foo")
     .animate("color:'red'", 2000)
     .delay(1000)
     .animate("backgroundColor:'rgb(0, 128, 0)'", 1000)
     .delay(1000)
     .animate("borderColor:'#0000ff'", 2000);

This code will animate the text color for 2 seconds, wait 1 second and then animate the background color during 1 second, wait 1 second and finally animate the border color for 2 seconds.

Predefined effects

Some predefined effects exists on GQuery class :

  • slideDown : Reveal all matched elements by adjusting their height.
  • slideUp : Hide all matched elements by adjusting their height.
  • slideToogle : Toggle the visibility of all matched elements by adjusting their height.
  • fadeIn() : Fade in all matched elements by adjusting their opacity.
  • fadeOut() : Fade out all matched elements by adjusting their opacity
  • fadeToggle() : Toggle the visibility of all matched elements by adjusting their opacity. Only the opacity is adjusted for this animation, meaning that all of the matched elements should already have some form of height and width associated with them.

Manipulating your widgets

GwtQuery allows you querying and manipulating the attached dom elements but also your GWT widgets ! You can select easily widgets and manipulate it, i.e. bind events handling, modify css, animate...

Querying the widgets

To find your widget, just make a query like you do for retrieving dom elements and call one of these two methods :
* widgets() : this method returns the list of widgets matching the query

//retrieve all attached gwt labels
List<Widget> allGwtLabels = $(".gwt-Label").widgets();

We use the fact that all Label widgets create an element having "gwt-Label" as css class to retrieve them.

  • the widget() method : if you know that your query will select only one widget or if you want to get the first widget matching the query :
public void createEmailTextBox(){
   //create your widget
   TextBox emailBox = new TextBox();
   //assign it a name
   emailBox.setName("email");
   //attach the widget to the DOM
   RootPanel.get().add(emailBox);
}

...

public String getEmail(){
   //do a query on a input element having email as name and get the associated widget
   TextBox emailBox = $("input[name='email']").widget();
   return emailBox.getValue();
}

This example shows that you are no longer oblige to maintain references to widgets since GQuery is able to find and return them. You just have to associate to your widgets something like an id, a css class or something else allowing to query them later.

Manipulate and enhance them

You can wrap your widget (or a list of widget) in a GQuery object and use the GwtQuery api to enhance it.

The code below adds a click handler to a Label :

Label label = new Label("Click on me and I will disappear");
$(label).click(new Function() {
            @Override
            public void f(Widget w) {
               //fade out the label
               $(w).fadeOut(1000);
             }
         });

Or your can use the live() method to make all Label (existing now or added in the future) clickable :

$(".gwt-Label").live(Event.ONCLICK, new Function() {
            @Override
            public void f(Widget w) {
               //fade out the label
               $(w).fadeOut(1000);
             }
         });

Using Plugins

GQuery supports a Plugin system for extension of the core GQuery object. [WritingPlugins] is covered in a separate document.

To use any plugin, you must do two things.
* statically import a reference to the Plugin's class literal
* invoke the method as which converts the basic GQuery interface into an instance of the plugin interface

The as method will return an instance of the plugin class with the same matched elements. GQuery plugins are required to inherit from the GQuery class itself, so a plugin encapsulates all of the methods of the GQuery object, as well as introducing new methods.

Example : the Effects plugin

GQuery comes with a plugin called Effects which parallels JQuery's Effects API.
As described above, import the reference to the Effect class literal and call the as method to receive a instance of the Effect plugin

import static com.google.gwt.query.client.plugins.Effects.Effects;

...

$("h1").click(new Function {
   public boolean f() {
     $("div").as(Effects).slideDown();
     return true;
   }
});

The code reveal the div elements by sliding down them when the user click on the h1 tags.

Check the javadoc of Effects class to get the list of available effects.

Plugins repository

Others plugins can be found in the gwtQuery-plugin site. Don't hesitate to use them or to commit a new one.

Ajax

Although GWT includes its own facilities for performing communications with the server, GQuery complements it adding jQuery syntax and builders to data-bind JSON and XML. Read the Gquery Ajax.

Data Binding

GQuery provides generators to produce builders and deal with Xml and Json as 'java' objects. Read the GQuery Data Binding.