Understanding JsInterop

274 views
Skip to first unread message

Scott Shumway

unread,
Feb 15, 2018, 4:21:59 AM2/15/18
to GWT Users
Greetings

I am trying to get a DOMRect from an Element. I can do this with JSNI, but have been unable to make a JsInterop version. Here's what I have:

public final class DOMRect extends JavaScriptObject
{
 // returns DOMRect or null
 public static native DOMRect getBoundingClientRect(Element element)
 /*-{
 return element.getBoundingClientRect && element.getBoundingClientRect();
 }-*/;

 protected DOMRect()
 {
 }

 public final native double getX()
 /*-{
 return this.x;
 }-*/;

 // etc.
}

I can make a JsType for DOMRect, no problem. The issue I'm having is with getBoundingClientRect(). This function may not exist which is why there is a null check. If I make an interface for getBoundingClientRect, I'm not allowed to cast Element to implement it. I can't extend Element, either. With JSNI, I am allowed to compile Javascript into Javascript, but I can't with JsInterop. It seems like a lot of trouble for 1 line of Javascript.

How can I do this? Thanks in advance...

Thomas Broyer

unread,
Feb 15, 2018, 4:53:45 AM2/15/18
to GWT Users


On Thursday, February 15, 2018 at 10:21:59 AM UTC+1, Scott Shumway wrote:
Greetings

I am trying to get a DOMRect from an Element. I can do this with JSNI, but have been unable to make a JsInterop version. Here's what I have:

public final class DOMRect extends JavaScriptObject
{
 // returns DOMRect or null
 public static native DOMRect getBoundingClientRect(Element element)
 /*-{
 return element.getBoundingClientRect && element.getBoundingClientRect();
 }-*/;

 protected DOMRect()
 {
 }

 public final native double getX()
 /*-{
 return this.x;
 }-*/;

 // etc.
}

I can make a JsType for DOMRect, no problem. The issue I'm having is with getBoundingClientRect(). This function may not exist which is why there is a null check.

You'll want a @JsProperty for the method so you can check whether it's null or not; and then either declare it also as a @JsMethod in parallel to call it, or have the @JsProperty return a @JsFunction (or then cast to an elemental2.dom.Element).
And you can hide the details the same way you did with JSNI, with a @JsOverlay:

@JsType(isNative=true, namespace=JsPackage.GLOBAL, name="Element")
class Element {
 
@JsProperty(name="getBoundingClientRect") private native Object getGetBoundingClientRect();
 
@JsMethod(name="getBoundingClientRect") private native DOMRect callGetBoundingClientRect();


 
@JsOverlay
 
public DOMRect getBoundingClientRect() {
   
return getGetBoundingClientRect() == null ? null : callGetBoundingClientRect();
 
}
}

or

@JsType(isNative=true, namespace=JsPackage.GLOBAL, name="Element")
class Element {
 
@JsProperty(name="getBoundingClientRect") public native GetBoundingClientRect getBoundingClientRect();


 
@JsFunction
 
interface GetBoundingClientRect {
   
public DOMRect invoke();
 
}
}


If I make an interface for getBoundingClientRect, I'm not allowed to cast Element to implement it.

How so‽
You cannot use JavaScriptObject#cast(), but you should be able to use a standard Java cast.
You might have to first cast to Object to please javac:

((HasGetBoundingClientRect) (Object) elt).getBoundingClientRect()

 
I can't extend Element, either. With JSNI, I am allowed to compile Javascript into Javascript, but I can't with JsInterop. It seems like a lot of trouble for 1 line of Javascript.

How can I do this? Thanks in advance...

getBoundingClientRect is supported in (literally) all browsers, so don't bother and just call the method: https://caniuse.com/#feat=getboundingclientrecthttps://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect#Browser_compatibility

Vassilis Virvilis

unread,
Feb 15, 2018, 5:01:41 AM2/15/18
to google-we...@googlegroups.com
Amazing trick!

Obvious if you think about it - but very difficult to think it initially (for us mere mortals).

   Vassilis

--
You received this message because you are subscribed to the Google Groups "GWT Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit+unsub...@googlegroups.com.
To post to this group, send email to google-web-toolkit@googlegroups.com.
Visit this group at https://groups.google.com/group/google-web-toolkit.
For more options, visit https://groups.google.com/d/optout.



--
Vassilis Virvilis

Thomas Broyer

unread,
Feb 15, 2018, 5:10:21 AM2/15/18
to GWT Users


On Thursday, February 15, 2018 at 11:01:41 AM UTC+1, Vassilis Virvilis wrote:
Amazing trick!

Obvious if you think about it - but very difficult to think it initially (for us mere mortals).

Well, when you write "element.getBoundingClientRect" in JS (without the parenthesis), this is exactly what you're doing: getting a reference to the function.
In JS, if you call it later, you need to either use .call(element) or .apply(element) to setup the appropriate 'this' element, or you first need to .bind(element) it to the element. I'm not sure how JsInterop works in this case, maybe (probably) my second example wouldn't actually work as it does neither of these (you could use an element2.core.Function to .call()/.apply() or .bind()).

That being said, I didn't came with this pattern by myself either, I believe I saw it somewhere in GWT's emulation library.

Scott Shumway

unread,
Feb 15, 2018, 1:19:44 PM2/15/18
to GWT Users
Thanks! I didn't think of casting to Object first... I'll give it a try. I generally turn on as many compiler warnings as I can stand to get my code to compile through a strict filter, but I was getting outright errors.

Also, namespace with "Element", Doh! of course...

Scott Shumway

unread,
Feb 20, 2018, 1:59:44 PM2/20/18
to GWT Users
I'm still unable to do this. I want to be able to get a DOMRect from a com.google.gwt.dom.client.Element with JsInterop. If I cast to this Element class, or even ((HasGetBoundingClientRect) (Object) element), I will get a (runtime) java.lang.ClassCastException. The cast to Object works, of course, it's the cast to HasGetBoundingClientRect.

Paul Stockley

unread,
Feb 21, 2018, 5:01:36 PM2/21/18
to GWT Users
Try using Js.uncheckedCast from jsinterop-base
Reply all
Reply to author
Forward
0 new messages