I'm doing a project in GWT to deploy in AppEngine and I'm getting a warning in Eclipse saying:
JavaScript parsing: Expected an identifier in JSNI
reference
Any ideas on what's causing this?
public void callFacebookAPI(String url) {
JsonpRequestBuilder requestBuilder = new JsonpRequestBuilder();
requestBuilder.requestObject(url, new AsyncCallback<FbUser>() {
public void onFailure(Throwable caught) {
System.out.println("FAIL" );
}
#Override
public void onSuccess(FbUser result) {
facebookUser = result;
System.out.println("Facebook name:" + facebookUser.getName());
}
});
}
private final native void doFbLoginFunction() /*-{
FB.login(function(response) {
if (response.authResponse) {
// connected
//return response.session;
var accessToken = response.accessToken;
var url = "http://graph.facebook.com/me?access_token=";
var facebookUrl = url + accessToken;
#com.google.gwt.smartpark.client.map.SmartPark::callFacebookAPI(Ljava/lang/String;Ljava/lang/
String;)(facebookUrl);
} else {
// cancelled
}
});
callFacebookAPI is not static so there must be something before the # in the reference in JSNI, e.g.
var that = this;
$wnd.FB.login($entry(function(response) {
// ...
that.#com.google.gwt.smartpark.client.map.SmartPack::callFacebookAPI(Ljava/lang/String;)(facebookUrl);
// ...
}));
Also, your callFacebookAPI takes a single argument, so the JSNI signature should have a single Ljava/lang/String;.
Related
I am new in JavaScript. I am developing JavaScript add-in for Office Online.
I am trying call some .NET dll in my add-in. I created in Visual Studio project "App for Office", created JavaScript add-in for test and trying use jQuery ajax for use .NET dll.
Javascript code for test:
(function () {
"use strict";
// The initialize function must be run each time a new page is loaded
Office.initialize = function (reason) {
$(document).ready(function () {
app.initialize();
$('#update-stocks').click(updateStocks);
});
};
function updateStocks() {
Excel.run(function (ctx) {
function CallHandlerSync(inputUrl, inputdata) {
$.ajax({
url: inputUrl,
contentType: "application/json; charset=utf-8",
data: inputdata,
async: false,
success: function (result) {
var objResult = $.parseJSON(result);
app.showNotification(objResult.Total);
},
error: function (e, ts, et) {
app.showNotification("Error...");
}
});
}
var number1 = 10;
var number2 = 20;
CallHandlerSync("Handler.ashx?RequestType=AddNum", { 'number1': number1, 'number2': number2 });
}).catch(function (error) {
app.showNotification("Error", error);
})
}
})();
Code in Handler.ashx
public class Handler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentEncoding = System.Text.Encoding.UTF8;
context.Response.ContentType = "text/html";
var strResult = string.Empty;
switch (context.Request.QueryString["RequestType"].Trim())
{
case "AddNum":
strResult = this.AddNumber(
Convert.ToInt32(context.Request["number1"]),
Convert.ToInt32(context.Request["number2"]));
break;
}
context.Response.Write(strResult);
}
public bool IsReusable
{
get
{
return false;
}
}
public string AddNumber(int number1, int number2)
{
int total = 0;
ClassLibrary1.Class1 sampleLib = new ClassLibrary1.Class1();
total = sampleLib.Add(number1, number2);
var jsonData = new
{
Total = total
};
JavaScriptSerializer javaScriptSerializer = new JavaScriptSerializer();
return javaScriptSerializer.Serialize(jsonData);
}
}
}
C# dll for test
public class Class1
{
public int Add(int X, int Y)
{
return X + Y;
}
}
This code compile Ok. But when I run program, I get ajax error. I have in response “Could not load file or assembly 'ClassLibrary1' or one of its dependencies. An attempt was made to load a program with an incorrect format”.
What I do wrong? Or I should use another way for my task?
An attempt was made to load a program with an incorrect format.
Typically this error is a x86 vs x64 compile issue. Try "Any CPU".
Right click Solution > Properties and target "Any CPU".
Say I define such a function:
function helloWorld(e) {
console.log("Hello " + e);
return;
}
How Can i be able to call it like this:
String funcName="helloWorld";
funcName(e);
In Java is there a style as simple as in Javascript?
This is known as Reflection:
import java.lang.reflect.Method;
public class Demo {
public static void main(String[] args) throws Exception{
Class[] parameterTypes = new Class[1];
parameterTypes[0] = String.class;
Method method1 = Demo.class.getMethod("method1", parameterTypes);
Demo demo = new Demo();
Object[] parameters = new Object[1];
parameters[0] = "message";
method1.invoke(demo , parameters);
}
public void method1(String message) {
System.out.println(message);
}
}
Taken from https://stackoverflow.com/a/4685609/5281806
I have used HybridWebView from XLabs to build a HybridWebView that can communicate with C# code. I have build custom renderers to do this. In simple terms I have:
iOS
public class HybridWebViewRenderer : ViewRenderer<HybridWebView, WKWebView>, IWKScriptMessageHandler
{
const string JavaScriptFunctionTemplate = "function {0}(){{window.webkit.messageHandlers.invokeAction.postMessage('{0}|' + JSON.stringify(arguments));}}";
protected override void OnElementChanged(ElementChangedEventArgs<HybridWebView> e)
{
base.OnElementChanged(e);
if (Control == null)
{
userController = new WKUserContentController();
foreach (var f in Element.RegisteredFunctions.Where(ff => !ff.IsInjected))
{
var script = new WKUserScript(new NSString(string.Format(JavaScriptFunctionTemplate, f.Name)), WKUserScriptInjectionTime.AtDocumentEnd, false);
userController.AddUserScript(script);
f.Injected();
}
userController.AddScriptMessageHandler(this, "invokeAction");
var config = new WKWebViewConfiguration { UserContentController = userController };
var webView = new WKWebView(Frame, config)
{
NavigationDelegate = new CustomWKNavigationDelegate(this.Element)
};
SetNativeControl(webView);
}
if (e.OldElement != null)
{
userController.RemoveAllUserScripts();
userController.RemoveScriptMessageHandler("invokeAction");
var hybridWebView = e.OldElement as HybridWebView;
hybridWebView.Cleanup();
}
if (e.NewElement != null)
{
Load(Element.Uri);
}
}
public void DidReceiveScriptMessage(WKUserContentController userContentController, WKScriptMessage message)
{
var bits = message.Body.ToString().Split('|');
if (bits.Count() == 2)
{
var result = Element.InvokeFunction(bits[0], bits[1]);
//How do I return result back to Javascript function?
}
}
the InvokeFunction method returns a value result which is a string.
How can I return this string result back to the javascript function which was injected?
Edit
Do I need to edit my JavaScriptFunctionTemplate I notice in the XLabs they have a similar template but append something to the end
Is there any reason why you couldn't simply 're-call' your function using the methods described here?
Their example:
void OnCallJavaScriptButtonClicked (object sender, EventArgs e)
{
...
int number = int.Parse (numberEntry.Text);
int end = int.Parse (stopEntry.Text);
webView.Eval (string.Format ("printMultiplicationTable({0}, {1})", number, end));
}
So yours would be something like:
const string JavaScriptFunctionTemplate = "function {0}(){{window.webkit.messageHandlers.invokeAction.postMessage('{0}|' + JSON.stringify(arguments));}}";
public void DidReceiveScriptMessage(WKUserContentController userContentController, WKScriptMessage message)
{
var bits = message.Body.ToString().Split('|');
if (bits.Count() == 2)
{
var result = Element.InvokeFunction(bits[0], bits[1]);
webView.Eval(string.Format ("JavaScriptFunctionTemplate({0})", result)); // or however your parameter structure is.
}
}
EDIT:
Just want to encorporate the LINK that the OP found as it looks to be a solid guide to the solution in Objective-C which is fairly straight forward to convert to Xamarin C#.
I need a way to pass a list of strings when a user clicks an icon from angular/script and send it to an MVC controller in .NET. This list does what it needs to then is supposed to download a file in my browser. I have learned that I cannot do this via AJAX and/or it get pretty messy.
Edit: the list of strings refers to a list of file ids that I am retrieving, then zipping up into one file, which is to be downloaded. I do not want to store this zipped file anywhere permanently.
I am open to ideas!
$http.post('document/downloadfiles', data).success(function () {/*success callback*/ });
[HttpPost]
public ActionResult DownloadFiles(List<string> fileUniqueIdentifiers)
{
var file = _service.ArchiveAndDownloadDocuments(fileUniqueIdentifiers);
file.Position = 0;
return new FileStreamResult(file, "application/force-download");
}
Ok, third-time lucky I guess?
(I think this'll be my last implementation sorry Jim - you'll have to work the rest out for yourself, I think I've given you more than enough free pointers for now... if you want more you can contact me and I'll charge you to write it! :P).
This version uses a cookie-based interchange, accepts the input strings (assuming they are filenames) from the javascript, stores these in the instance class along with the token as key, then assembles the ZipFile in-memory (without writing to disk), and then returns the zipfile as a Content Result. For efficiency you could remove the actual token checks against the GUID list and just check against the key in the file list. Obviously you probably won't want the filenames hard-coded in that javascript as I've done, but you can work that part out for yourself.
Hint: Create a database table with identifier/filepath pairs and use the identifiers to lookup the individual file paths after the request is sent to the server...
View Part (I added mine to index.cshtml):
<script type="text/javascript">
function sendStringandGetFiles() {
var files = ['c:\\temp\\afile.txt', 'c:\\temp\\afile2.txt', 'c:\\temp\\afile3.txt'];
$.ajax({
type: "POST",
url: "/Home/GetFile",
contentType: 'application/json',
data: JSON.stringify(files),
success: function (result) {
//alert("Yes This worked! - " + result);
window.location = "/Home/GetFile";
}
});
}
</script>
<h5>Just something to click</h5>
<button onclick="sendStringandGetFiles()">Send String and Get Files</button>
Then Controller Part (I used HomeController.cs)
[AcceptVerbs(HttpVerbs.Post)]
public string GetFile(string[] strings)
{
Guid token = Guid.NewGuid();
InMemoryInstances instance = InMemoryInstances.Instance;
instance.addToken(token.ToString());
instance.addFiles(token.ToString(), strings);
HttpCookie cookie = new HttpCookie("CookieToken");
cookie.Value = token.ToString();
this.ControllerContext.HttpContext.Response.Cookies.Add(cookie);
return token.ToString();
}
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult GetFile()
{
InMemoryInstances instance = InMemoryInstances.Instance;
if (this.ControllerContext.HttpContext.Request.Cookies.AllKeys.Contains("CookieToken"))
{
HttpCookie cookie = this.ControllerContext.HttpContext.Request.Cookies["CookieToken"];
if (instance.checkToken(cookie.Value))
{
cookie.Expires = DateTime.Now.AddDays(-1);
this.ControllerContext.HttpContext.Response.Cookies.Add(cookie);
MemoryStream ms = new MemoryStream();
string[] filenames = instance.getFiles(cookie.Value);
using (ZipArchive zs = new ZipArchive(ms,ZipArchiveMode.Create, true))
{
for (int i=0;i < filenames.Length; i++)
zs.CreateEntryFromFile(filenames[i], Path.GetFileName(filenames[i]));
}
FileContentResult resultContent = new FileContentResult(ms.ToArray(),"application/zip");
instance.removeFiles(cookie.Value);
resultContent.FileDownloadName = "ARandomlyGeneratedFileNameHere.zip";
return resultContent;
} else
{
return View("Index");
}
}
else
{
return View("Index");
}
}
InMemoryInstances Class:
public class InMemoryInstances
{
private static volatile InMemoryInstances instance;
private static object syncRoot = new Object();
private List<Guid> activeTokens;
private NameValueCollection filesByKeyCollection;
private InMemoryInstances()
{
activeTokens = new List<Guid>();
filesByKeyCollection = new NameValueCollection();
}
public static InMemoryInstances Instance
{
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
instance = new InMemoryInstances();
}
}
return instance;
}
}
public bool checkToken(string token)
{
return activeTokens.Contains(new Guid(token));
}
public string[] getFiles(string token)
{
return filesByKeyCollection.GetValues(token);
}
public bool addFiles(string token, string[] files)
{
for (int i = 0; i < files.Length; i++)
filesByKeyCollection.Add(token, files[i]);
return true;
}
public bool addToken(string token)
{
activeTokens.Add(new Guid(token));
return true;
}
public bool removeFiles(string token)
{
filesByKeyCollection.Remove(token);
return true;
}
public bool removeToken(string token)
{
return activeTokens.Remove(new Guid(token));
}
}
Hope this helps!
I normally wouldn't go to this length of effort to help, but I'm home sick and feel like writing some code, so here's an implementation of what I think you're asking for. Here I'm using token exchange to track the file interchange for a specific user storing the data in a singleton instance, you could use another method (e.g. database token storage) if you wanted...
View Part (I added mine to index.cshtml):
<script type="text/javascript">
function sendStringandGetFiles() {
var strings = ['One String', 'Two String', 'Three String'];
$.ajax({
type: "POST",
url: "/Home/GetFile",
contentType: 'application/json',
data: JSON.stringify(strings),
success: function (result) {
//alert("Yes This worked! - " + result);
window.location = "/Home/GetFile?token=" + result;
}
});
}
</script>
<h5>Just something to click</h5>
<button onclick="sendStringandGetFiles()">Send String and Get Files</button>
Then, Controller part (I used HomeController.cs):
[AcceptVerbs(HttpVerbs.Post)]
public string GetFile(string[] strings)
{
for (int i = 0; i < strings.Length; i++)
{
// Do some stuff with string array here.
}
Guid token = Guid.NewGuid();
InMemoryInstances instance = InMemoryInstances.Instance;
instance.addToken(token.ToString());
return token.ToString();
}
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult GetFile(string token)
{
string filename = #"c:\temp\afile.txt";
InMemoryInstances instance = InMemoryInstances.Instance;
if (instance.checkToken(token))
{
instance.removeToken(token);
FileStreamResult resultStream = new FileStreamResult(new FileStream(filename, FileMode.Open, FileAccess.Read), "txt/plain");
resultStream.FileDownloadName = Path.GetFileName(filename);
return resultStream;
}
else
{
return View("Index");
}
}
InMemoryInstances Class:
public class InMemoryInstances
{
private static volatile InMemoryInstances instance;
private static object syncRoot = new Object();
private List<Guid> activeTokens;
private InMemoryInstances()
{
activeTokens = new List<Guid>();
}
public static InMemoryInstances Instance
{
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
instance = new InMemoryInstances();
}
}
return instance;
}
}
public bool checkToken(string token)
{
return activeTokens.Contains(new Guid(token));
}
public bool addToken(string token)
{
activeTokens.Add(new Guid(token));
return true;
}
public bool removeToken(string token)
{
return activeTokens.Remove(new Guid(token));
}
}
Hope this helps!
I also wrote yet another implementation which uses cookies to perform the same operation (incase you wanted to store the information client-side instead of using a query-string, yes, I'm slightly bored)...
View Part (I added mine to index.cshtml):
<script type="text/javascript">
function sendStringandGetFiles() {
var strings = ['One String', 'Two String', 'Three String'];
$.ajax({
type: "POST",
url: "/Home/GetFile",
contentType: 'application/json',
data: JSON.stringify(strings),
success: function (result) {
//alert("Yes This worked! - " + result);
window.location = "/Home/GetFile?token=" + result;
}
});
}
</script>
<h5>Just something to click</h5>
<button onclick="sendStringandGetFiles()">Send String and Get Files</button>
Then Controller Part (I used HomeController.cs)
[AcceptVerbs(HttpVerbs.Post)]
public string GetFile(string[] strings)
{
for (int i = 0; i < strings.Length; i++)
{
// Do some stuff with string array here.
}
Guid token = Guid.NewGuid();
InMemoryInstances instance = InMemoryInstances.Instance;
instance.addToken(token.ToString());
HttpCookie cookie = new HttpCookie("CookieToken");
cookie.Value = token.ToString();
this.ControllerContext.HttpContext.Response.Cookies.Add(cookie);
return token.ToString();
}
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult GetFile()
{
string filename = #"c:\temp\afile.txt";
InMemoryInstances instance = InMemoryInstances.Instance;
if (this.ControllerContext.HttpContext.Request.Cookies.AllKeys.Contains("CookieToken"))
{
HttpCookie cookie = this.ControllerContext.HttpContext.Request.Cookies["CookieToken"];
if (instance.checkToken(cookie.Value))
{
cookie.Expires = DateTime.Now.AddDays(-1);
this.ControllerContext.HttpContext.Response.Cookies.Add(cookie);
FileStreamResult resultStream = new FileStreamResult(new FileStream(filename, FileMode.Open, FileAccess.Read), "txt/plain");
resultStream.FileDownloadName = Path.GetFileName(filename);
return resultStream;
} else
{
return View("Index");
}
}
else
{
return View("Index");
}
}
InMemoryInstances Class:
public class InMemoryInstances
{
private static volatile InMemoryInstances instance;
private static object syncRoot = new Object();
private List<Guid> activeTokens;
private InMemoryInstances()
{
activeTokens = new List<Guid>();
}
public static InMemoryInstances Instance
{
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
instance = new InMemoryInstances();
}
}
return instance;
}
}
public bool checkToken(string token)
{
return activeTokens.Contains(new Guid(token));
}
public bool addToken(string token)
{
activeTokens.Add(new Guid(token));
return true;
}
public bool removeToken(string token)
{
return activeTokens.Remove(new Guid(token));
}
}
Maybe that is better if you want to hide the token interchange from the browser address bar?
In my android application, i have called one javascript method from html page to java page.
this.start = function ()
{
try
{
Mynamespace.myapi.getvalue("myvalue", {
onSuccess: function (data)
{
value= JSON.parse(data);
alert("called");
},
onFailure: function (error) { }
});
}
catch (err) { }
if (value== null) { value= new Object();
};
In the above, getvalue method is called in my java class and returned some values, but before getting the value inside the OnSuccess/OnFailure, the below line is called. How to wait the method up to the callback is called?
if (value== null) { value= new Object();
private class LongOperation extends AsyncTask<String, Void, String>
{
protected void onPreExecute()
{
progressDialog = new ProgressDialog(activity.this);
progressDialog.setTitle("Processing...");
progressDialog.setMessage("Please wait...");
progressDialog.setCancelable(true);
progressDialog.show();
}
protected String doInBackground(String... params)
{
try
{
//Getting data from server
}
catch (Exception e) {
e.printStackTrace();
}
return null;
}
protected void onPostExecute(String result)
{
progressDialog.dismiss();
}
}
How to call this
ProgressDialog progressDialog;
LongOperation mytask = null;
mytask = new LongOperation();
mytask.execute();
I have analyzed more about my query. Finally i got a solution. String that i have loaded with webview was having more single quotes so unable to load with webview. So instead of calling Success failure callback, the next line is called.
Now I have replaced the single quotes "\'" by "\'" in my java class. Working fine. :-)