i'm new using monotouch.
My problem is i want call a javascript function from a monotouch function and javascript function could call a monotouch function too.
I believe that with objective c this problem is possible, but i need making it with monotouch.
Help me please.
any help is thank for advance
To invoke Javascript code running in the UIWebView from your application, use the EvaluateJavascript method, like this:
myView.EvaluateJavaScript ("a = 1;");
To call back into your C# code, the only option is to hook up to the ShouldStartLoad property like this:
myView.ShouldStartLoad = myHandler;
[...]
bool myHandler (UIWebView webView, NSUrlRequest request, UIWebViewNavigationType navType)
{
// Determine what to do here based on the #request and #navType
}
You can of course, also use anonymous methods if you want to access local variables easily:
myView.ShouldStartLoad = (webView, request, navType) => {
// Determine here what to do
}
In the Javascript side, if you want to call back to Mono, you then set the location.href property to a "special" url, like this:
// Javascript code:
location.href = "myapp://action?par1=abc&par2=def"
The information will be available on the request object: request.Url.AbsoluteString
I just released MonoTouch JsBridge to make this easier. It allows you to add event listeners and fire events between the native side and the UIWebView. It was inspired by Titanium.
https://github.com/crdeutsch/MonoTouch-JsBridge
I haven't tried it in monotouch, but it should be the same as in ObjC:
UIWebView.EvaluateJavascript
Related
I have been playing with Revit API through pyRevit for quite a while (so, using Python) and I now also need to use C# for some parts of my code.
I am trying to access the VersionNumber property, provided by the Application class. Doing that using pyRevit was quite straightforward, as all I did was
app = __revit__.Application
That's it. I can do it anywhere, it works fine.
Now, I look at C# examples illustrating this (I'm a total C# beginner, by the way), and all examples seem to indicate the same way of proceeding:
UIApplication uiApp = commandData.Application;
Application app = uiApp.Application;
with commandData being an ExternalCommandData object passed as an argument in the Execute method of the class.
My question is: how can I access commandData if I'm not in the Execute method? i.e. if commandData isn't passed as an argument. Can I just instantiate an Application object, just as I did with Python? How?
Thanks a lot,
Arnaud.
Whether you are in a context of Revit's ExternalCommand or not you need access to the UIApplication. You are correct that ExternalCommand provides it via commandData. You can also obtain it from an idling event like so:
private static void OnIdling(object sender, IdlingEventArgs e)
{
var app = (UIApplication)sender;
}
It is also accessible from an ExternalEventHandler `Execute method like so:
public void Execute(UIApplication app)
{
}
What I want to do:
I want to call a javaScript function from a Bean-function
Then I want to pause my Bean-function
Then the JavaScript function do it's own thing and returns stuff back to the bean
Then the Bean-function wakes up and handle the result
Details:
I am using JSF 2.2, and ICEfaces 4.2.0.
I am using JavaScriptRunner.runScript() to call a javascript function. (This works well)
Calling bean function from JavaScript works well
According to the docs about JavaScriptRunner.runScript() the function should "Send immediately Javascript code to the client for evaluation and execution"
Problem:
The problem is that the javaScript function won't be called before the bean code has ended.
Is it possible to start the javaScript function by interrupting the bean-function?
EDIT:
Added an example Bean of how I how thought it should work, if it helps:
public class MyBean {
public String callJavaScriptFunctionAndWaitAndHandleResult() {
// Call a javascript function from the bean
callJavaScriptFunction();
// Waits untill the javascript has returned some stuff
pause(); // <-- IS IT POSSIBLE TO WAIT HERE AND RUN A JAVASCIPT FUNCTION?
// Handle the result you got from the javascript function
handleResultFromJavaScript();
}
}
Disclaimer: Code in the answer will contain untested code in PrimeFaces flavour and 'pseudo code'. Since I do not use/run IceFaces nor do I have the intention to, I cannot (will not) test the code and will only provide the PrimeFaces counterparts as an (untested) example
Answer
You seem to be stuck trying to get a technical solution to work that cannot work. JSF cannot 'pause' things and will only return data at the end of the bean method that is called. You are most likely mislead by the statement in the IcesFaces documentation
"Send immediately Javascript code to the client for evaluation and execution"
This cannot work due to the way JSF works and it is sort of not really good English. The developers should have stated something like
"Send Javascript code to the client at the end of the method call for immediate evaluation and execution"
The immediate means that it is not some <script> .... </script> that gets added to the page and that can be executed again and again by e.g. calling a function that is defined in the script. It does not mean you cannot call existing javasript functions (ones that are already in your DOM) from the returned script (effectively that is what we will be using)
So how to solve your problem. Start by breaking the method down in two, lets call them step1 and step2
void step1() {
// Do things
// return javascript
}
void step2() {
// Do other things using values that will be posted from the client by javascript
}
How to return javascript/call javascript from a bean is an existing Q/A here in Stackoverflow. For the IcesFaces counterpart I refer to their documentation. A PrimeFaces example is
PrimeFaces.current().executeScript("alert('This onload script is added from backing bean.'); clientSideFunction();");
But at the end of the javascript you want to call a server side method in a bean from javascript. The opposite of what you need in step one.
A PrimeFaces example being
<p:remoteCommand name="clientSideFunction" action="#{bean.step2}" />
And in since in calling step2() you want to pass parameters to the bean, you need to implement this as well.
clientSideFunction([{name:'x', value:10}, {name:'y', value:20}]);
You can use javascript variables in there (e.g. a complete json string in a variable) and need to process these variables (especially see the 'update' at the end)
I need to call a java bean method from a client side javascript library. Is there a way to call ssjs from csjs library?
something like this that works in csjs
var test = #{javascript:getConfig.getKeyValuesList("param")};
You want to use the Remote Service tool in the Ext. Library. That lets you define a function in SSJS and call it from CSJS.
There's discussion of it here:
http://www.notesin9.com/2014/05/21/tim-explains-json-rpc-codefortim/
There's an old NotesIn9 Video should should still be very valid:
http://www.notesin9.com/2011/08/25/notesin9-033-introduction-to-remote-services-in-xpages/
You can do it the way you showed in your example like
var test = #{javascript:yourBean.getSomething()};
The SSJS code gets executed first, the result gets inserted into CSJS code and send to client.
It depends on your use case if that can be a solution for you.
Your a bit modified example
var test = ['#{javascript:getConfig.getKeyValuesList("param").join("', '")}'];
would execute the methode getKeyValuesList(), return a List of strings, .join() would convert it to a string like "aaa', 'bbb', 'ccc" and send the following resulting code to client:
var test = ['aaa', 'bbb', 'ccc'];
I do this with a combination of CSJS libraries where I define objects with properties and methods and then on a custom control (usually the one with the resource for the library) I add a scriptBlock for getting the data into my client side objects. As frank says this only happens when the page is loaded but for configuration data like what you seem to be getting that works just fine.
Here is a sample csjs class for your library:
var appConfig = {
param1 : "",
param2 : ""
}
Then this is the scriptBlock code:
<xp:scriptBlock>
<xp:this.value><![CDATA[
// setup config parameters
appConfig.param1 = '#{javascript:getConfig.getKeyValuesList("param1")}';
appConfig.param2 = '#{javascript:getConfig.getKeyValuesList("param2")}';
})
]]></xp:this.value>
</xp:scriptBlock>
Happy coding.
So, I am working on a class called DMFWriteExportData and trying to get it run in Batch.
I am at a point where I need to figure out a way to get rid of fieldControl and the reason being it does not let me Run the class on the server and throws an error because it is not supposed to be running on server? (not sure)
Error: "The method Dialog Control.control cannot be called from the server; use methods on the Dialog Field class instead."
-
public Object dialog()
{
DialogRunbase dialog = new DialogRunbase("#DMF372", this);
FormStringControl control;
dialogExecution = dialog.addFieldValue(extendedTypeStr(dMFExecutionId), executionId);
control = dialogExecution.fieldControl();
control.mandatory(true);
control.displayLength(24);
control.registerOverrideMethod(methodstr(FormStringControl, lookup), methodstr(DMFWriteExecutionParameters, executionIdLookup), this);
control.registerOverrideMethod(methodstr(FormStringControl, modified), methodstr(DMFWriteExecutionParameters, executionIdModified), this);
dialogdescription=dialog.addFieldValue(extendedTypeStr(description),DMFExecution::find(executionId).Description);
dialogdescription.enabled(false);
return dialog;
}
I am wondering:
If it is actually true that this class cannot be set to server
when using control.registerOverrideMethod
If yes, what would be the ideal solution to overcome this situation,
is there any way I can create custom lookups? I see there is method
called registerOverrideMethod in the DialogField class.
Any help would be appreciated.
Thanks,
Khosla
The reason why you cannot (and should) run the code above in batch is because it uses dialog controls that only exist on the client side. You should never run this kind of code on server. Please check runon property of your class and set it to called from.
However, I assume you are using RunBaseBatch. If you are on AX 2012, you should use the SysOperation framework instead.
When using RunBaseBatch, all code is on the same class. This way, you are mixing client side code (main method, dialog method etc) with the code that should run on server (run method). For this reason you should set the "runon" property of the class to CalledFrom, not Server.
You can solve this by using SysOperation which applies the Model View Controller (MVC) pattern that neatly sepperates the two.
For an introduction to SysOperation, check my blog here:
AX2012: SysOperation introduction
I have a little Greasemonkey script that communicates with a servlet on (my) server. The servlet is sending back JavaScript code, which I eval() in the onload handler of the GM_xmlhttpRequest.
So far, all is working fine. Now, I'd like to use send another GM_xmlhttpRequest from within that eval()ed code. and here I'm stuck. I do not see any error, but all GM_* functions appear not to be working from within the eval(responsetext).
If I hard code the GM_xmlhttpRequest in the onload handler (no eval()), it is working fine.
It is possible to work around this problem, you can call GM_* functions with setTimeout set to 0 from eval'ed code. Try something like:
function myFunction()
{
GMXmlHttpRequest(...)
}
eval('setTimeout(myFunction, 0)');
A better solution is to extend Function.prototype with a function called safeCall that does this for you. Whenever you have any eval'ed code that will call into GM_* functions you'll need to have safeCall somewhere in that call chain.
Greasemonkey (GM) is hosting the user script, which means that it can add functions and objects to the user script, when you call eval() the script runs unhosted (the vanilla JavaScript is running it) and you don't get the GM API inside of it.
There is another solution. I have the similar problem, I don't want to put all my logic in user script, because if I change them, user need to update them by themselves. So what I want to do is separating the main logic from loading logic, the main logic will be loaded at beginning by the user script and eval them.
So I made a function "sendRequest", which is a wrapper of GM_xmlhttpRequest(), I need it anyway, because the method, server url and onError callback are always same for my application, so I just put them into my "sendRequest" function to make the xmlhttprequest simple.
In the main logic javascript code, which is loaded from server, there is no greasemonkey function call at all. If I want to for example communicate with server, I will call sendRequest instead. It works.