Passing Object Literal to Javascript method ?

359 views
Skip to first unread message

Ed

unread,
Oct 2, 2013, 4:12:25 PM10/2/13
to google-we...@googlegroups.com
Please some help on the following.
How to pass an Object literal to a javascript function

I have a javascript function that looks like:
public final native CssHolder perform(Element element, int duration) /*-{
return $wnd.CssMod.perform(element, {opacity: 0.2}); 
}-*/;

This works if I call it from java code.
How can I pass in the Object literal "{opacity: 0.2}" as argument in the above?

So I want something like:
public final native CssHolder  perform(Element element, int duration, Object args) /*-{
return $wnd.CssMod.perform(element, args); 
}-*/;

But what should "args" be ?
I tried to pass in a json data string and eval() it, like 
return $wnd.CssMod.perform(element, eval(args)); 
Or pass in a json string like:
perform(button, 3, "[ \"opacity\" : \"0.2\" ]"
etc...
But it all results in some strange Javascript error :(..
- Ed



Jens

unread,
Oct 2, 2013, 8:12:01 PM10/2/13
to google-we...@googlegroups.com
I think you have to write

public final native CssHolder  perform(Element element, int duration, String args) /*-{
  return $wnd.CssMod.perform(element, eval('obj = ' + args + ';'));
}-*/;

perform(element, "{ \"opacity\":2}");




Maybe the following also works: 

public final native CssHolder  perform(Element element, int duration, JavaScriptObject params) /*-{
  return $wnd.CssMod.perform(element, params);
}-*/;

perform(element, JsonUtils.safeEval("{ \"opacity\":2}"));

With the above you could probably also create a Params.Builder that creates the JSO and then use that JSO directly as parameter.


-- J.

Ed Bras

unread,
Oct 3, 2013, 5:55:35 AM10/3/13
to google-we...@googlegroups.com

@Jens: thanks, I am going for the latter options, that seems to work well and safe. 
The builder pattern was exactly why I want the above construction ;)  (using the GWT css classes for the naming)

I am just considering if directly creating a JavascriptObject through a Builder class wouldn't be better considering performance, as it will skip the Json parsing. 
I am just not sure how to do this, looking in to it now. If you have any idea, let me know please.

Ed Bras

unread,
Oct 3, 2013, 6:32:48 AM10/3/13
to google-we...@googlegroups.com
Played some more and I create a literal Js Object, or some called Option Js object, like this:


private JavaScriptObject createOptions(final String name, final String value) {
return addOptions(JavaScriptObject.createObject(), name, value);
}

private native JavaScriptObject addOptions(final JavaScriptObject obj, final String name, final String value) /*-{
obj[name] = value;
return obj;
}-*/;

So use it like:
 options = createOptions("opacity", "0.5");

Or
options = JavaScriptObject.createObject();
addOptions("opacity", "0.5");
addOptions("width", "100");

Works well... what do you think?
I will probably create a Factory/Facade that offers both options: through Json String data, or directly through JavascriptObject.

Jens

unread,
Oct 3, 2013, 9:57:34 AM10/3/13
to google-we...@googlegroups.com
I would build it like:

Mutable version:

class Options extends JavaScriptObject {
   public native Options with(String option, String value) /*-{
      this[option] = value;
      return this;
   }-*/;
}

Options options = Options.createObject()
    .with("opacity", "0.5")
    .with("width", "100");



An immutable Options class would also be possible but as it is GWT you are dealing with things are never really immutable thanks to JSNI magic. Using JSNI magic you could hide the JavaScriptObject from Java code but still use it inside your perform() method, e.g.

class Options {
   private JavaScriptObject nativePeer;

   // Builder class having the "with(.., ..)" method and which configures the native peer

   // getter, etc. to inspect the native peer if needed.
}

public native CssHolder perform(Element e, int duration, Options options) /*-{
   var nativeOptions = options.@<full qualified class name>::nativePeer;
   return $wnd.CssMod.perform(e, duration, nativeOptions);
}-*/;



-- J.

Ed Bras

unread,
Oct 3, 2013, 10:05:17 AM10/3/13
to google-we...@googlegroups.com
Fluent api, nicee....Thanks for your ideas.

Ed Bras

unread,
Oct 3, 2013, 1:37:40 PM10/3/13
to google-we...@googlegroups.com
To Wrap it up: I ended up having a PropertiesBuilder interface:
public interface PropertiesBuilder<T> extends Builder {
PropertiesBuilder<T> set(String key, T value);
}

and a Js version:
public final class JsPropertyBuilder implements PropertiesBuilder<Object>, IsJavaScriptObject {
private final JavaScriptObject jsObject;
public JsPropertyBuilder() {
this.jsObject = JavaScriptObject.createObject();
}
public JavaScriptObject asJavaScriptObject() {
return getJsObject();
}
public JsPropertyBuilder set(String key, Object value) {
UtilsJsni.addProperty(getJsObject(), key, value);
return this;
}
private JavaScriptObject getJsObject() {
return jsObject;
}
}

And the interface :
 public interface IsJavaScriptObject {
JavaScriptObject asJavaScriptObject();
 }

The component facade contains a method that accepts the IsJavaScriptObject as input, which makes it mockable (through the GWTBridge) and such that can I use it in my unit tests.



Ed

unread,
Oct 3, 2013, 3:53:18 PM10/3/13
to google-we...@googlegroups.com
Next challenge: how to provde a callback function as property?
In Javascript you have something like:
CssMod.perform(element, 1.5, {width:100, onComplete:myFunction});
function myFunction() {
    console.log("finished");
}

But how can I do this in GWT Java code :( ? That is: specify a "link" to a Callback method that should be called




Jens

unread,
Oct 3, 2013, 4:55:03 PM10/3/13
to google-we...@googlegroups.com
Add a Callback parameter to your JSNI method and call it from a pure JavaScript callback function.

public native CssHolder perform(Element e, int duration, JavaScriptObject options, Callback callback) /*-{
  options.onComplete = function() {
     callback.@<full qualified class name>::onComplete()();
     // maybe cleanup options.onComplete here
  };
  return CssMod.perform(e, duration, options);
}-*/;


-- J.

Ed Bras

unread,
Oct 3, 2013, 5:12:31 PM10/3/13
to google-we...@googlegroups.com
Thanks @Jens, I was just playing with it and it was driving me crazy as it didn't work and because of your example I noticed that the "dot" before the @ was missing :(... I hate this cryptic JS errors :(...

Anyway, I ended up with this method added to the PropertyBuilder that works:

private static native JavaScriptObject addPropertyIntern(final JavaScriptObject obj, final String name, final SimpleCommand value) /*-{
obj[name] = function() {
value.@com.bla.SimpleCommand::execute()();
}
return obj;
}-*/;


Ed Bras

unread,
Oct 3, 2013, 5:18:53 PM10/3/13
to google-we...@googlegroups.com
@Jens: btw, do you know how to tell Eclipse to "not" format the native java methods ? (CTR+SHIFT+ F)
I noticed @Thomas mentioning on SO that it's probably done by the JS formatter in Eclipse. But I wasn't able to disable it. 
The only way I got it disabled by using the Eclipse tags: @formatter:off and @formatter:on.
Message has been deleted

Ed Bras

unread,
Oct 4, 2013, 9:01:04 AM10/4/13
to google-we...@googlegroups.com
What is the correct way to check if a java object is not null in javascript?
Exampe:
private native  performIntern(JsArray<? extends Element> elements, int duration, JavaScriptObject options,  HasOnComplete command) /*-{
                var func = null;
if (typeof  command !== 'undefined') { 
func = function() {
command.@com.bla.HasOnComplete::onComplete()(); 
}
}
return $wnd._CMod.perform(elements, duration, options,  func);  
}-*/;

It will never enter the if if the command isn't null :(..
I also tried things like "if (command)" or first assign command to another variable... but no luck and can't seem to find a matching example in code some where. I noticed that GWT uses a global function "defined()" in for example JavaScriptObject, but no idea where to find the source.
BTW: the if is entered if I do something like "if (duration > 0)"..... such that the command is called...

Thomas Broyer

unread,
Oct 4, 2013, 9:08:08 AM10/4/13
to google-we...@googlegroups.com
if (command != null) ?

Ed Bras

unread,
Oct 4, 2013, 10:05:00 AM10/4/13
to google-we...@googlegroups.com
@Thomas: that seems to work (very obvious btw). I forgot to mention that I tried that before, and didn't work, but I remember that it works once (calling the callback), but I think that has another cause. Thanks...
Anyway, there isn't a special operation needed in this case, I though I might have to access the parameter like "<parameter name>@pack"..... (tried that but didn't work either).

Ed Bras

unread,
Oct 4, 2013, 10:08:04 AM10/4/13
to google-we...@googlegroups.com
BTW: where can I find an example of using the method JavascriptObject.createFunction()?
I think it can be used to wrap a java instance and forward a js call to a call in the instance, but don't understand how this can be done through this function creation method (can't find any example on the net).

Jens

unread,
Oct 4, 2013, 10:28:04 AM10/4/13
to google-we...@googlegroups.com
BTW: where can I find an example of using the method JavascriptObject.createFunction()?
I think it can be used to wrap a java instance and forward a js call to a call in the instance, but don't understand how this can be done through this function creation method (can't find any example on the net).

I am really not a JS expert but I have a hard time imagine a use case for an empty function returned by JavaScriptObject.createFunction(). Although JavaScript is a dynamic language I am pretty sure you can not redefine a method's empty body after its defined.

Because its useless you won't find examples for it and IMHO can just be deleted in GWT.

-- J.

Ed Bras

unread,
Oct 4, 2013, 10:33:03 AM10/4/13
to google-we...@googlegroups.com
@Jens: I was thinking the same, but "somebody" has added with a goal I thought, so there would be any use of it ;)


--
You received this message because you are subscribed to a topic in the Google Groups "Google Web Toolkit" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/google-web-toolkit/xOrOUcTas3Y/unsubscribe.
To unsubscribe from this group and all its topics, send an email to google-web-tool...@googlegroups.com.
To post to this group, send email to google-we...@googlegroups.com.
Visit this group at http://groups.google.com/group/google-web-toolkit.
For more options, visit https://groups.google.com/groups/opt_out.

Thomas Broyer

unread,
Oct 4, 2013, 10:44:00 AM10/4/13
to google-we...@googlegroups.com
Something similar (but can't remember if it actually used createFunction) was used to "reset" an XHR's onreadystatechange to avoid some leak or crash in some browser (IE?)


On Friday, October 4, 2013 4:33:03 PM UTC+2, Ed wrote:
@Jens: I was thinking the same, but "somebody" has added with a goal I thought, so there would be any use of it ;)
On Fri, Oct 4, 2013 at 4:28 PM, Jens <jens.ne...@gmail.com> wrote:
BTW: where can I find an example of using the method JavascriptObject.createFunction()?
I think it can be used to wrap a java instance and forward a js call to a call in the instance, but don't understand how this can be done through this function creation method (can't find any example on the net).

I am really not a JS expert but I have a hard time imagine a use case for an empty function returned by JavaScriptObject.createFunction(). Although JavaScript is a dynamic language I am pretty sure you can not redefine a method's empty body after its defined.

Because its useless you won't find examples for it and IMHO can just be deleted in GWT.

-- J.

--
You received this message because you are subscribed to a topic in the Google Groups "Google Web Toolkit" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/google-web-toolkit/xOrOUcTas3Y/unsubscribe.
To unsubscribe from this group and all its topics, send an email to google-web-toolkit+unsub...@googlegroups.com.

Jens

unread,
Oct 4, 2013, 10:52:00 AM10/4/13
to google-we...@googlegroups.com
yeah just found the reason:


But it looks like its already refactored and JavaScriptObject.createFunction() isn't used anymore.

-- J.

Ed Bras

unread,
Oct 6, 2013, 8:51:05 AM10/6/13
to google-we...@googlegroups.com
The external js lib I am using as the following condtion on an input arg I specify:
    if (value instanceof Array) {
This is a problem for me, as the array I pass isn't seen an array as GWT runs in an iframe (such that the lib complaints it's not an arry).
Like @Thomas explains in his post.
Is there any workaround?

Ed

unread,
Oct 7, 2013, 6:37:43 PM10/7/13
to google-we...@googlegroups.com
FYI: they changes the "instanceof Array" statement in the external lib ;)
Reply all
Reply to author
Forward
0 new messages