Reputation: 1835
General Aim: call some nonstatic java method from javascript
Description: To find gwt's widget on DOM in Java Applet code and call it's java method(non static)
JSObject win = JSObject.getWindow(this);
JSObject doc = (JSObject) win.getMember("document");
JSObject gwtWidget = (JSObject) doc.call("getElementsByName", widgetName);
//todo: have possibility to call `exported` java method over here, smth like:
//Object[] params = new Object[1];
//params[0] = widgetName;
//Object result = gwtWidget.call("exportedJavaMethod", params);
//todo: or just call global ($wnd) static JSNI bridge method:
//Object result = win.call("exportedJavaMethod", params);
//
The problem is: I can find by widget's id not the widget, but it's DivElement which does not have any exported instanced methods.
My widget class is Exportable (gwt-export):
@Export(value="somewidget")
public class SomeWidget extends SimplePanel implements ..., Exportable {
private final String id = "id_some_widget_" + count++;
private static int count = 0;
public SomeWidget () {
getElement().setAttribute("name", id);
getElement().setId(id);
}
...
public static Element getInstanceById(String elementId) {
Element someWidget= DOM.getElementById(elementId);
return someWidget;
}
public String getSomeInstancedData() {
return "useful_inner_data" + this.id;
}
So, for example I'd like to find the concrete widget added to DOM and call nonstatic method getSomeInstancedData()
in javascript. Is it possible at all?
Suppose smth like:
var someWidget = document.getElementById(widgetId);
alert(someWidget.getSomeInstancedData());
//or:
var someWidgetExported = com.mypackage.widgets.somewidget.getInstanceById(listenerId);
alert(someWidgetExported.getSomeInstancedData());
In Base module I write:
ExporterUtil.exportAll();
There is a View(ViewWithSomeWidget.ui.xml) that contains this widget:
... base:Form base:SomeWidget ui:field="someWidget" ... ... /base:SomeWidget ...
When SomeWidget does not implement Exportable, project runs well, but I couldn't call nonstatic methods of found widget's DIV element.
By the time, to solve the problem SomeWidget implements Exportable, but progect doesn't show View with the SomeWidget well because of ClassCastException using deferred binding:
ClassCastException: com.mypackage.widgets.SomeWidgetExporterImpl cannot be cast to com.mypackage.widgets.SomeWidget
So, probably there are any other methods to find widget's javascript object and call it's exported java method? In any ways, any idea is much appreciated.
Upvotes: 2
Views: 3968
Reputation: 957
You can declare a javascript function, which will fire the non-static method.
For example:
package com.example;
public class Layout extends VLayout() {
private String nonStaticVar = "nonStaticVar";
public Layout() {
declareMethod(this);
}
//Method which declares non-static method in javascript
public native void declareMethod(Layout layout) /*-{
var layout = layout;
$wnd.doSomething = function(someString) {
[email protected]::doSomething(Ljava/lang/String;)(someString);
}
}-*/;
//Non static method which is being called
public String doSomething(String someString) {
//Do something, e.g. set var in this instantiated class, or output stuff
this.nonStaticVar = someString;
Window.alert(someString);
}
}
Now, calling doSomething("bla"); from javascript will call your non-static method.
Upvotes: 11
Reputation: 41
you can define an own jsmethod on the div element, that can call a widget-method
@Export(value="somewidget")
public class SomeWidget extends SimplePanel implements ..., Exportable {
private final String id = "id_some_widget_" + count++;
private static int count = 0;
public SomeWidget () {
getElement().setAttribute("name", id);
getElement().setId(id);
attachInstanceHook(getElement());
}
...
public String getSomeInstancedData() {
return "useful_inner_data" + this.id;
}
private native void attachInstanceHook(Element element) /*-{
var elem = element;
var widget = this;
elem.getWidgetData = function () {
[email protected]::getSomeInstancedData()();
};
}-*/;
and your js-code should look like this:
var someWidget = document.getElementById(widgetId); //the id of the div element
alert(someWidget.getWidgetData());
Upvotes: 4
Reputation: 16263
instead of trying to fetch the widget through its DOM element, inject its Java instance first to the global scope and refer to it:
public class SomeWidget extends SimplePanel implements ..., Exportable {
//...
public SomeWidget () {
getElement().setAttribute("name", id);
getElement().setId(id);
attachToGlobalScope(id, this);
}
private native void attachToGlobalScope(String id, SomeWidget instance) /*-{
$wnd.shared[id] = instance;
}-*/;
//...
}
than later, update the corresponding fetch in the Applet API layer:
JSObject win = JSObject.getWindow(this);
JSObject shared = (JSObject) win.getMember("shared");
Widget widgetRef = (Widget) shared.getMember(widgetId);
disclaimer: this somewhat crooked solution relays on JavaScript global scope variables, which is considered bad practice in general, but here acts as the only common scope, thus abused for objects storage.
Upvotes: 1