Aug 23, 2012

Using third-party JS libraries in SmartGWT


Although GWT frameworks and include it their words "richest set of GWT UI components", in fact, it turns out, for example, that their ability to visualization a very, very limited or practically absent in the free version (SmartGWT). As a result, finding the desired functionality in the libraries of JavaScript, in sight seeing such wonderful things as Raphaël and D3.
In fact, it turns out that the use of Smart GWT's extensive server-side components are not as easy as expected. How to do this is described below.

First, came the idea to use HtmlFlow, especially since this class supports the method:

setEvalScriptBlocks(Boolean evalScriptBlocks)
After futile attempts, i found information that this method is not suitable for our purposes.

JSNI - JavaScript Native Interface best suited for this task. In short, you create a native Java method and conclude your JavaScript code in a special comments:


public static native void drawChart(String chartId) /*-{
    ... your code ...
}-*/;   
Inside the method, you can access to class fields, using the signature:

obj.@className::fieldName
Also you can access to static and instance class methods:

[instance-expr.]@class-name::method-name(param-signature)(arguments)
I want to mention one more important thing. Your JSNI JavaScript code will be slightly different from the standard JS code that may need to use $wnd to access window object and $doc to access document object. If you get a JavaScript error on the page, "JavaScript library is not found", even though it has access from WEB-server - this is exactly the case.

Another detail - you can not use java arays even primitive types like String [] or int [] in your JSNI code. It is unclear why the developers are not yet implemented this feature. Instead it is proposed to use JsArrays:


native JsArray getNativeArray() /*-{
    return [ { x: 0, y: 1}, { x: 2, y: 3}, { x: 4, y: 5}, ];
}-* /;
or can write method, that also return JSON structure, for example:

public String getJSONPoints(int metricIndex, long start, long stop)
{
    Collection<Double> points = pointsStorage
        .get(metricIndex)
        .getValues(start, stop);
    String s = "[";
    for (Double point : points)
    {
        s += point + ",";
    }
    s += "]";
    return s;
}
and then in JavaScript:

var jsonPoints = eval(this.@class-name::getPoints(IDD)(metricIndex, 
        start.getTime(), stop.getTime()));
Knowing these basics will allow to write JSNI code. Writing JSNI methods is a powerful technique, but developers recommend used it sparingly.

References:

  1. HtmlFlow: http://www.smartclient.com/smartgwt/javadoc/com/smartgwt/client/widgets/HTMLFlow.html;
  2. JSNI presentation;
  3. JSNI Coding Basics: https://developers.google.com/web-toolkit/doc/latest/DevGuideCodingBasicsJSNI

5 comments:

  1. Probably there are errors in the text, so I will be very grateful if you point to them

    ReplyDelete
  2. Hmmm... You are solved your task very interesting way =) I'm thought offer you solve based on JSONP, although, you very near its =)

    I hope that you understand me =)))))

    ReplyDelete
  3. Could you outline how a solution via JSONP could look like?

    ReplyDelete
  4. Thank, You Артём. Solution based on REST\JSON for integration JS library with SmartGWT really looks more concise. But those who do not have such a possibility can find a solution here.

    ReplyDelete
  5. Heiko, meaning a solution that receives data is by calling not a java method, but which uses a REST service with data in JSON format.Because GWT requests to the server asynchronously, and receive data at the library means synchronous, You have to write additional code that leads to the GWT request to synchronous form. Since REST request \ response are synchronous, we have a significant advantage.

    ReplyDelete