GWT JSNI - Java To Javascript Back To Java Results in undefined params - javascript

I have racked my brain on this for the better part of two days. I've read through the documentation on JSNI here as well as a few different blog posts on JSNI and passing variables like this one and nothing indicates I'm doing anything wrong. Essentially what I'm trying to do is call from my GWT Client Side class to a javascript method which I'm exporting to javascript as my class loads. That method takes params from another JS method and stores them on the instance of the Java class that I passed. That seems to work. But, once I reference those methods back in my java code, they're undefined. I believe that what is happening is that my Java Class instance is getting lost somehow after the JS finishes. Here's some code to help explain the workflow...
I have a Java Class named ProfileWidgee. That class has a method to set local variables for location, lattitude, and longitude. That method name is...
public void handleTargetPicked(String mloc, String mlat, String mlng) {
loc = mloc.equalsIgnoreCase("undefined") ? "" : mloc;
lat = mlat.equalsIgnoreCase("undefined") ? "" : mlat;
lng = mlng.equalsIgnoreCase("undefined") ? "" : mlng;
Window.alert("setting on js side" + loc + lat + lng);
}
That method gets exported to the JS as a function using a JSNI method called exportMyFunction...
public static native void exportMyFunction(ProfileWidgee instance)/*-{
$wnd.handleTargetPicked = $entry(
instance.#com.n.j.client.widgees.profile.ProfileWidgee::handleTargetPicked(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;));
}-*/;
That all seems to go fine. It exports and I'm able to call the handleTargetPicked in my JS as follows...
handleTargetPicked(encodeURIComponent(place.formatted_address),
encodeURIComponent(place.geometry.location.lat()),
encodeURIComponent(place.geometry.location.lng()));
All of this seems to work and the Window.alert() displays the correct values. That leads me to believe that it has the appropriate instance of my class and that it is setting the variables appropriately. Later on though as I'm back in my Java class, I try and reference those variables and they always come back as 'undefined.'
Window.alert("reading on the java side" + pw.getLoc() + pw.getLat() + pw.getLng());
This results in 'undefined' for all three values. So my big question is ... is it possible to set a value in your Java class from the JS side and then use that value later in your class?

I just ran into a somewhat similar situation like this and happened to see your post.
I couldn't see any solutions suggested anywhere, so tried to debug it myself.
What I saw was, 'this' variable was pointing to Window rather than the object instance.
So rather than calling the method directly like e.g. handleTargetPicked(arg1, arg2), I used method.call() passing the context like e.g. handleTargetPicked.call(instance, arg1, arg2). That kind of approach solved the issue for me. Hope that helps.

Related

Pass Component Name as Argument and then attach method (not working?)

Maybe I'm not using the right terms/names for my searches but I have not been able to find anything on this topic. I would have thought this would be an easy thing to find. What I'm doing is passing a component name to a function and then trying to use the component's name by attaching a method to it. I have confirmed (via Dev Tools) that the name is correctly being passed but when I use the variable and attach the method the specific request does not work. If I 'hard-code' the exact component name to the method it works perfectly. This makes me think the (various) ways I've been trying to attach the method to the variable name is incorrect (see various attempts below). Can you offer some direction here? Thank you.
Passing to Function ...
const grid_name = "grid_GroupA";
console.log(grid_name); // Shows grid_GroupA
msg_max(newItem, grid_name);
Function (only listing relevant parts)
function msg_max(newItem, grid_target) {
console.log(grid_target); // Shows grid_GroupA
// grid_GroupA.data.add(newItem); // This works ...
// grid_target.data.add(newItem); // This does not work
// (grid_target).data.add(newItem); // This does not work
// [grid_target].data.add(newItem); // This does not work
// grid_target + '.data.add(newItem)'; // This does not work
Thank you ...
Edit ...
In my attempt to provide detail I hope I haven't confused the issue.
In essence, my question is if I can type this exact string
grid_GroupA.data.add(newItem);
and it works for my function, how can I place a variable with the exact string "grid_GroupA" in front of ".data.add(newItem);" and have it seen the same as the line of code that works? Maybe my lack of knowledge here is getting in the way but isn't the line of code that works just a string that is then used to 'find' the object? So, if that assumption is correct, how do I create that same string with the variable? If my assumption is wrong I am a willing learner so I will be all ears. Thank you.
I do not see how grid_target is an object. You are passing grid_name(which is a string) to the function, so grid_target will have no data property, because string doesn't have such a member.
P.S. snake_case is bad option for JavaScript, consider using cameCase instead

How to use C# SQLDataReader Object in JavaScript

My goal is to return a C# SQLDataReader object from a C# function into a JavaScript.
In the JavaScript part I would like to read String-Values from the DataReader.
Is this possible?
This is how I tested:
var tools = Tools.GetExtension("LoadTheNETAssembly");
reader = tools.ExecProcedure("exec Loc.dbo.spASTVSwitch '" + sExtension + "', '" + sChannel + "'");
So I called the "ExecProcedure" Function in the C# Code.
This works, but I do not know how to handle the returned SQLDataReader.
In the past I returned a ADODB-Connection object from a Delphi-Function into JavaScript.
This worked perfectly and I would like to replace the Delphi-Part by C#.
I have made a app in winforms where I made all pages in static html,css,javascript. I need to bind my javascript based list from the app where my whole backend code in c#. I simply done ComVisibleAttribute(True) on the page. My C# code expose a StringBuilder that have all the result.
I simply call .ToString() from javascript on that object and I can see the response in javacript. Same time my Breakpoint hits in C# (.cs code) so this is how I get my work done as I want.
In your situation you are calling C# code from your JavaScript code. You can expose every object (which is public) to the Javascript Code. For example read this article https://www.codeproject.com/Articles/35373/VB-NET-C-and-JavaScript-communication
You can call your C# object from Javascript something like this
window.external.reader.MyFunction()
Remember that object that you want to use in c# should be publicly accessible and must be static.

j2v8: creating new instance of binded object

Our teams is currently under consideration of which JavaScript Engine Bridge to use. We are choosing between LiquidCore and J2V8.
My question is concerning j2v8. Supposedly, I have to create several instances of some java class in JavaScript, how can one achieve this in j2v8 using standard instantiation annotation (new ClassName())? In liquidcore you can bind some class, that extends JSFuction, with super constructor:
JSFunction(JSContext ctx, final String methodName, final Class<?extends JSObject> instanceClass)
and register property with desired class name like this:
jsBaseContext.getJsContext().property("WebSocket", this);
and then on calling:
var x = new WebSocket();
java method methodName will fire, where we'll get new instanceClass as JSValue object as parameter, already binded and ready to use in javascript.
Since no one is going to discuss this topic, i'll answer myself.
This feature is not currently considered to be added in official J2V8 release, however there is a branch on Mizumi's pull request. So, have a look, if you've faced similar issues.

Connecting Javascript properties to Java object

The Problem
I am trying to feed a Java object into a script that would normally operate on the Document Object Model (DOM) of a web page. For the most part this functions as intended. However I have encountered a problem when dealing with attributes/properties of the DOM elements.
A particular property chain of interest is somediv.firstChild.href. What I can't figure out is how to get the firstChild property value dynamically. The simplest way I can think of at the moment is to use source.replaceAll("firstChild", "firstChild()"); to force the firstChild property to invoke the function firstChild() instead. However this will eventually open up a new can of worms.
The Question
How do I define an object that can be passed to a javascript function that can be operated on via the DOM?
Background
Learnings from C#
Before diving into Java I had learnt C#. In C# the concept of setters and getters is quite prevalent. If this interface method were available in Java my problem would be solved.
public string firstChild {
get { return this.getFirstChild(); }
set { this.setFirstChild(value); }
}
Current Implementation
The script is currently invoked by wrapping it in a function where I can pass in the window and document Java objects into the function's workspace.
document is a special top-level version of SpoofedDomElement (that extends it) but is functionally identical to the sample shown below. window is another object with minimal functions that handle event listeners.
Javascript (snippet) to operate on DOM
var somediv = document.createElement('div');
somediv.style.display = "block"
somediv.innerHTML="<a href='/mywork/server/test.html'>The Test Server Homepage</a>";
var linkvalue = somediv.firstChild.href;
This snippet is stored as the string theOriginalSource and used in the next section.
Java code to evaluate Javascript
String wrappedSource = "var scriptToInvoke = function(window, document){"
+ "\n" + theOriginalSource // from above
+ "\n};"
Object result = invocable.invokeFunction("scriptToInvoke", window, document);
This snippet wraps the javascript snippet so that I can pass in objects to use as window and document.
Java classes that spoof DOM elements
public class SpoofedDomElement {
public SpoofedDomElement firstChild;
public String id;
public String innerHtml;
public String href;
public SpoofedStyleProperties style = new SpoofedStyleProperties();
public String tagname;
...
}
public class SpoofedStyleProperties {
public String background = "transparent none repeat scroll 0% 0% auto padding-box border-box";
public String color = null;
public String display = "inline";
}
The above classes handle irrelevant parts of the code just fine (such as the assignment somediv.style.display = "block"). But it starts to fall apart when handling the values of firstChild or innerHtml when either value is changed.
Past Work
N.B. I include this section in all my questions to document what I have tried for future SO users who get here by Google. This might help someone reach a solution by aiding brainstorming.
Attempted Solutions
I have attempted to use a framework (HtmlUnit) to evaluate the Javascript. But I couldn't control which Javascript snippets were executed.
Potential Solutions
The following are questions that I am currently researching to find a solution. If I find anything I will report back.
Is there a way to emulate C# getter/setter behaviour in Java?
Can Javascript evaluate firstChild as a function?
Is there a way to create a wrapper within Javascript with getter/setters that can invoke my Java class's functions?
Is there an Apache Commons library for Nashorn (or similar) that isn't as heavy as the complete simulation frameworks (such as Selenium)?
It appears that you're trying to implement friendly access of script objects from Java code as well as trying to provide script-friendly API on top of java library/libraries.
For the first part [ script object access from Java ]
Apart from javax.script.Invocable interface, you can use JSObject. Nashorn exposes script objects as instances of jdk.nashorn.api.scripting.JSObject/.ScriptObjectMirror
https://docs.oracle.com/javase/8/docs/jdk/api/nashorn/jdk/nashorn/api/scripting/ScriptObjectMirror.html
For the second part [ friendlier access of Java objects from scripts ]
You can write script friendly wrappers in script itself using "JSAdapter".
Doc and Example:
https://wiki.openjdk.java.net/display/Nashorn/Nashorn+extensions#Nashornextensions-JSAdapterconstructor
If you'd prefer to do in Java, you can implement your own jdk.nashorn.api.scripting.JSObject/.AbstractJSObject.
Doc and Example:
https://wiki.openjdk.java.net/display/Nashorn/Nashorn+extensions#Nashornextensions-jsobject
Other nashorn specific script extensions may also be used to trap unknown property/method access in per object basis:
noSuchProperty hook in any script object:
https://wiki.openjdk.java.net/display/Nashorn/Nashorn+extensions#Nashornextensions-noSuchProperty
noSuchMethod hook in any script object:
https://wiki.openjdk.java.net/display/Nashorn/Nashorn+extensions#Nashornextensions-noSuchMethod
Object.bindProperties:
There script API extension can be used to bind properties of one object to another - the source object could be a Java object as well.
https://wiki.openjdk.java.net/display/Nashorn/Nashorn+extensions#Nashornextensions-Object.bindProperties
With jdk9, there is more flexible inter-language linking possible with Dynalink API [ http://openjdk.java.net/jeps/276 ]
See also:
https://blogs.oracle.com/sundararajan/entry/dynamic_linker_api_for_the
https://blogs.oracle.com/sundararajan/entry/writing_pluggable_dynalink_linker_and
https://blogs.oracle.com/sundararajan/entry/nashorn_javascript_access_to_python
There are dynalink samples "samples/dynalink" directory of Nashorn OpenJDK repository:
http://hg.openjdk.java.net/jdk9/dev/nashorn/file/4a6ee1185fc8/samples/dynalink

Making a method public in JavaScript. Why this syntax?

I was studying TinyMCE code and stumbled upon this way of exposing public methods:
tinymce.extend(this, {
execCommand : execCommand,
queryCommandState : queryCommandState,
queryCommandValue : queryCommandValue,
addCommands : addCommands
});
What is the benefit of writing the above if the below code can be used instead (with fewer lines of code and less execution time required for the same task!)
this.execCommand = execCommand;
this.queryCommandState = queryCommandState;
this.queryCommandValue = queryCommandValue;
this.addCommands = addCommands;
Or even shorter, somewhere in the declaration of an object:
execCommand: execCommand,
queryCommandState: queryCommandState,
queryCommandValue: queryCommandValue,
addCommands: addCommands
Where's the catch?
Well, one thing that jumps out at me is the first sample that you have there is the method in which the TinyMCE expects its arguments for its extend function.
Glancing at the source of extend, it checks each key value pair for undefined, only adding them to the object if they're defined. So, there's a little bit of added functionality that can be useful when extending a class.

Categories

Resources