Writing JavaScript with DWR

DWR generates Javascript code that is similar to the Java code that you remoted, using the <create ... > element, in your dwr.xml file.

The biggest challenge in creating a remote interface to match Java code across Ajax is the (usually) asynchronous nature of Ajax, compared to the synchronous nature of a normal Java call.

DWR solves this problem by introducing a callback function that is called when the data is returned from the server.

There are 2 recommended ways to make a call using DWR. Either by appending a callback function to the parameter list or by appending a call meta data object.

It is also possible to put the callback function at the start of the parameter list, however this option is not advised because there are some issues when dealing with automatic http objects (see "Alternative Method"). This method mostly remains for backwards compatibility.

Simple Callback Functions

Suppose we have a Java method that looks like this:

public class Remote {
    public String getData(int index) { ... }
}

We can use this from Javascript as follows:

<script type="text/javascript"
    src="[WEBAPP]/dwr/interface/Remote.js"> </script>
<script type="text/javascript"
    src="[WEBAPP]/dwr/engine.js"> </script>
...

function handleGetData(str) {
  alert(str);
}

Remote.getData(42, handleGetData);

'42' is just the parameter to the getData() Java function - see above.

Alternatively you can use the all-in-one-line version:

Remote.getData(42, function(str) { alert(str); });

Call Meta-Data Objects

The alternative syntax is to make use of a call meta-data object that specifies the callback function and (optionally) other options. The example above would become:

Remote.getData(42, {
  callback:function(str) { alert(str); }
});

This method has some advantages: Depending on your style it may be easier to read, but more importantly it allows you to specify extra call options.

Timeouts and Handling Errors

In addition to the callback meta data you can also specify a timeout and an errorHandler. For example:

Remote.getData(42, {
  callback:function(str) { alert(str); },
  timeout:5000,
  errorHandler:function(message) { alert("Oops: " + message); }
});

Finding the callback method

There are some instances when it might not be tricky to distinguish between the various callback placement options. (Remember that Javascript does not support overloaded functions). For example:

Remote.method({ timeout:3 }, { errorHandler:somefunc });

One of the 2 parameters is a bean parameter and the other is a call meta-data object but we have no way of telling which. In a cross-browser world we have to assume that null == undefined. So currently, the rules are:

Creating Javascript objects to match Java objects

Suppose you have an exposed Java method like this:

public class Remote {
  public void setPerson(Person p) {
    this.person = p;
  }
}

And Person looks like this:

public Person {
  private String name;
  private int age;
  private Date[] appointments;
  // getters and setters ...
}

Then you can call this from Javascript like this:

var p = {
  name:"Fred Bloggs",
  age:42,
  appointments:[ new Date(), new Date("1 Jan 2008") ]
};
Remote.setPerson(p);

Any fields missing from the Javascript representation will be left unset in the Java version.

Since the setter returned 'void' we did not need to use a callback and could just leave it out. If you want to be notified of the completion of a server-side method that returns void then you can include a callback method. Obviously DWR will not pass any data to it.