I have the following javascript method:
myFunc = function(callback) { callback.call(this, "hello", "world"); }
and I´m passing a java object that implements the 'call' method. In the java call method I get the two parameters "hello" and "world", but not 'this' (of course). Is there a way to access 'this' from java?
I´m interfacing java with d3.js and d3 has lots of callbacks in this way and 'this' is where d3 stores a selection.
Thanks
I´m not actually coding in Java but JRuby. In order to make a Java example
I´ll have to simplify my code bellow. Maybe this can help some. If not,
I´ll try to do a Java example.
# Function f1 will call the callback methods cb1 and cb2 with 'this' variable
# This is just a notation for creating javascript function. It calls
# #browser.executeJavaScriptAndReturnValue(scrpt), whith the function
# body (everything between EOT) modified to make a valid javascript script.
# f1 is a function with 2 arguments cb1, and cb2 which should be the
# callback functions
f1 = B.function(<<-EOT)
(cb1, cb2) {
cb1.call(this, "banana", "milk");
cb2.call(this, "arroz", "feijao");
}
EOT
# Proc is a closure. It receives two arguments |food1, food2|. This will
# become a java object per JRuby´s magic
proc = Proc.new { |food1, food2| puts "I hate #{food1} and #{food2}" }
# now call method f1 passing proc as the first argument and the block as
# the second argument. So cb1 = proc and cb2 = <the block bellow>. Method
# 'send' grabs the given arguments, converts them to java objects and then
# calls jxBrowser 'invoke' method with the given arguments.
f1.send(proc) { |food1, food2| puts "eu gosto de #{food1} e #{food2}" }
The result of executing this code is:
I hate banana and milk
eu gosto de arroz e feijao
As can be seen, the 'this' variable is just gone... I would like to be able to
capture the 'this' variable somehow in order to be able to use the context in the blocks. I´ve managed to make a workaround that allows capturing the 'this' variable, but it requires wrapping the block in another javascript function.
The whole idea of this code is to allow a JRuby developer to write Ruby code and get this code executed in jxBrowser without needing to use any javascript. Examples of this can already be seen by downloading mdarray-sol GEM, or going to https://github.com/rbotafogo/mdarray-sol. There you can see multiple examples of using d3.js with JRuby.
Please make sure that you follow the instruction at https://jxbrowser.support.teamdev.com/support/solutions/articles/9000013062-calling-java-from-javascript and inject your Java object with the call() method correctly:
Java code:
browser.addScriptContextListener(new ScriptContextAdapter() {
#Override
public void onScriptContextCreated(ScriptContextEvent event) {
Browser browser = event.getBrowser();
JSValue window = browser.executeJavaScriptAndReturnValue("window");
window.asObject().setProperty("java", new JavaObject());
}
});
...
public static class JavaObject {
public void call(JSValue window, String message) {
System.out.println(message);
}
}
JavaScript code:
window.java.call(window, 'Hello Java!');
Related
I have a method in .NET (GetDataStationParts), which I declare with 2 parameters, I want to call it from a JavaScript, and I use the InvokeMethodAsyn function in this way:
const { data } = require("jquery");
function GetParteScrap()
{
var idestacionjs = document.getElementById('getestacion');
var idmodelojs = document.getElementById('getmodelo');
var tablascrap = DotNet.InvokeMethodAsyn("YMMScrapSystem", "GetDataStationParts", idestacionjs, idmodelojs);
console.log(tablascrap);
}
To do it, I base it on an example on the web but I'm not sure where it gets the DotNet object to then invoke the method, the intention of my code is that after selecting parameters of 2 , go to the database and execute a SQL-level function, which will return a table, with the function GetDataStationParts, I try to give it the functionality to execute my method at the DB level as follows
[JSInvokable]
public async Task<IEnumerable<GetEstacionParte>>GetDataStationParts(int modelo, int estacion)
{
var resul = await _context.Set<GetEstacionParte>().FromSqlInterpolated($"SELECT * FROM dbo.GetEstacionParte({modelo},{estacion})").ToArrayAsync();
return resul;
}
The SQL level function works correctly, but when running the application at the console level in the browser, it throws the following error, where it indicates that the function is not defined
Where could the error be? Thank you for reading
require() is not a feature that is built into the browser. Javascript environment does not understand how to handle require(), In Node.js by Default this function is available.
I suspect you most probably missing some reference here. You can either download require.js from here & link with your application or use below script tag.
<script src="https://requirejs.org/docs/release/2.3.5/minified/require.js"></script>
here is the code of an alloy controller written in two different ways. Although the both work the same, Which one might be best practice?
example 1 of controller.js:
var currentState = true;
$.getState = function(){
return currentState;
}
example 2 of controller.js:
var currentState = true;
exports.getState = function(){
return currentState;
}
Titanium is based on the CommonJS framework. The exports variable is a special variable used typically to expose a public API in a class object. So when you want to expose a method of doSomething() on the MyModule.js class you would use the exports variable like this:
exports.doSomething() = function(args) {
//Some really cool method here
};
Then reference that class using
var myModule = require('MyModule');
myModule.doSomething();
However when referencing a view object the typical way to reference the is using the $. shortcut. You can see they prefer that method in the official documentation.
http://docs.appcelerator.com/platform/latest/#!/guide/Alloy_XML_Markup
The $ variable holds a reference to your controller instance. It also contains some references to all indexed views (understand, views for which you supplied an index in you xml markup).
Both ways are strictly equivalent as, during the compilation, Alloy will merge the content of the exports with your controller referenced in $. Adding them directly to the instance won't change a thing.
Neverthless, developers are used to see the public API as the set of functions exported via the special variable exports; Thus, I will recommend to keep using it in a clean and clear way (for instance, defining your functions in your module scope, and only expose them at the end or beginning of your controller).
function myFunction1 () { }
function myFunction2 () { }
function myFunction3 () { }
exports.myFunction1 = myFunction1;
exports.myFunction3 = myFunction3;
Thereby, your API is quite clear for people diving into your source code. (A readMe file is also highly recommended :) ).
I want to contain all my commands in a map and map from the command to a function doing the job (just a standard dispatch table). I started with the following code:
package main
import "fmt"
func hello() {
fmt.Print("Hello World!")
}
func list() {
for key, _ := range whatever {
fmt.Print(key)
}
}
var whatever = map[string](func()) {
"hello": hello,
"list": list,
}
However, it fails to compile because there is a recursive reference between the function and the structure. Trying to forward-declare the function fails with an error about re-definition when it is defined, and the map is at top-level. How do you define structures like this and initialize them on top level without having to use an init() function.
I see no good explanation in the language definition.
The forward-reference that exists is for "external" functions and it does not compile when I try to forward-declare the function.
I find no way to forward-declare the variable either.
Update: I'm looking for a solution that do not require you to populate the variable explicitly when you start the program nor in an init() function. Not sure if that is possible at all, but it works in all comparable languages I know of.
Update 2: FigmentEngine suggested an approach that I gave as answer below. It can handle recursive types and also allow static initialization of the map of all commands.
As you might already have found, the Go specifications states (my emphasis):
if the initializer of A depends on B, A will be set after B. Dependency analysis does not depend on the actual values of the items being initialized, only on their appearance in the source. A depends on B if the value of A contains a mention of B, contains a value whose initializer mentions B, or mentions a function that mentions B, recursively. It is an error if such dependencies form a cycle.
So, no, it is not possible to do what you are trying to do. Issue 1817 mentions this problem, and Russ Cox does say that the approach in Go might occasionally be over-restrictive. But it is clear and well defined, and workarounds are available.
So, the way to go around it is still by using init(). Sorry.
Based on the suggestion by FigmentEngine above, it is actually possible to create a statically initialized array of commands. You have, however, to pre-declare a type that you pass to the functions. I give the re-written example below, since it is likely to be useful to others.
Let's call the new type Context. It can contain a circular reference as below.
type Context struct {
commands map[string]func(Context)
}
Once that is done, it is possible to declare the array on top level like this:
var context = Context {
commands: map[string]func(Context) {
"hello": hello,
"list": list,
},
}
Note that it is perfectly OK to refer to functions defined later in the file, so we can now introduce the functions:
func hello(ctx Context) {
fmt.Print("Hello World!")
}
func list(ctx Context) {
for key, _ := range ctx.commands {
fmt.Print(key)
}
}
With that done, we can create a main function that will call each of the functions in the declared context:
func main() {
for key, fn := range context.commands {
fmt.Printf("Calling %q\n", key)
fn(context)
}
}
Just populate the map inside a function before using list(). Like that.
Sry I did not see that you wrote "without init()": that is not possible.
I have some questions with a particular structure of a program I'm writing.
I'm using a Remote Object to make a remote call to a Rails method (using WebOrb). The problem arises in the way that I get my data back.
Basically I have a function, getConditions, in which I add an event listener to my remote call and then I make the remote call. However, what I want to do is to get that data back in getConditions so I can return it. This is a problem because I only access the event result data in the event handler. Here's some basic code describing this issue:
public function getConditions():Array
{
remoteObject.getConditions.addEventListener("result", onConditionResult);
remoteObject.getConditions();
//Here is where I want to get my event.result data back
}
public function onConditionResult(event:ResultEvent):void
{
//Here's the data that I want
event.result;
}
How can I achieve this data turn-about?
Remote calls in flex are always asynchronous so you won't be able to call getConditions() and wait there for the result. You have to use a function closure to process the results, either by means of an event handler than you declare elsewhere or a dynamic one created immediately within getConditions(), like so:
remoteObject.getConditions.addEventListener("result", function(event:ResultEvent):void {
// Run the code that you would want to when process the result.
});
remoteObject.getConditions();
The advantage of doing the above is that you would be able to "see" parameters passed to getConditions() or the result of any logic that happened before addEventListener() in the function closure. This however, takes a slight performance hit compared to declaring an explicit function (for that exact reason).
I should also add that doing so requires you to clean up after yourselves to make sure that you are not creating a new listener for every request.
you do it like this
public function getConditions():Array
{
remoteObject.getConditions.addEventListener("result", onConditionResult);
remoteObject.getConditions();
}
public function callMyExtraFunction(data:Object):void
{
//Here is where you want to get your event.result data back
}
public function onConditionResult(event:ResultEvent):void
{
//Here's the data that you want
var data:Object = event.result;
callMyExtraFunction(data);
}
You could make use of Call Responder like so :
<s:CallResponder id="getOperationsResult"/>
then use these lines to get the result from get operations
getOperationResult.token = remoteObject.getOperation();
this creates the call and returns the result stores it in getOpresult
whnever u want to access this u can call that token or getOperationResult.lastResult
Hope that helps
Chris
I'm developing a Flex application and am having some trouble working with asynchronous calls. This is what I would like to be able do:
[Bindable] var fooTypes : ArrayCollection();
for each (var fooType : FooType in getFooTypes()) {
fooType.fooCount = getFooCountForType(fooType);
itemTypes.addItem(fooType);
}
The issue I'm running into is that both getFooTypes and getFooCountForType are asynchronous calls to a web service. I understand how to populate fooTypes by setting a Responder and using ResultEvent, but how can I call another service using the result? Are there any suggestions/patterns/frameworks for handling this?
If possible, I Strongly recommed re-working your remote services to return all the data you need in one swoop.
But, if you do not feel that is possible or practical for whatever reason, I would recommend doing some type of remote call chaining.
Add all the "remote calls" you want to make in array. Call the first one. In the result handler process the results and then pop the next one and call it.
I'm a bit unclear from your code sample when you are calling the remote call, but I assume it part of the getFooCountForType method. Conceptually I would do something like this. Define the array of calls to make:
public var callsToMake : Array = new Array();
cache the currently in process fooType:
public var fooType : FooType;
Do your loop and store the results:
for each (var fooType : FooType in getFooTypes()) {
callsToMake.push(fooType);
// based on your code sample I'm unclear if adding the fooTypes to itemTypes is best done here or in the result handler
itemTypes.addItem(fooType);
}
Then call the remote handler and save the foo you're processing:
fooType = callsToMake.pop();
getFooCountForType(fooTypeToProcess);
In the result handler do something like this:
// process results, possibly by setting
fooType.fooCount = results.someResult;
and call the remote method again:
fooType = callsToMake.pop();
getFooCountForType(fooTypeToProcess);