pass data to webview
Has anyone ever been able to pass data back and forth between app.js and an open webview.
I've been going over this for a few days now and none of the examples work.
I'm trying to pass data from the webview to app.js and then data back from app.js back to webview
I have successfully been able to pass data from an open webview back to app.js, but I have not been able to pass data from app.js to an open webview.
Such a basic requirement it should be easy to do! Hmm.
To get data from open webview to app.js I am doing the following
my.js
Ti.App.fireEvent('helloWorld', { data : "Hello World" );
app.js
Ti.App.addEventListener('helloWorld', function(passedData)
{
Titanium.API.info('I said:' + passedData.data);
});
So, anyone know how to get data from app.js into an open webview?
.
UPDATED: See below for a working answer.
9 Answers
-
Ok finally got it. This is a way to pass data back and forth.
This sends data round trip from webview to app.js and then back again.
app.js // This creates the webview and opens it in a window var webView = Titanium.UI.createWebView({url:'index.html'}); var appWin = Titanium.UI.createWindow({fullscreen: true}); appWin.add(webView); appWin.open(); // This registers an event listener that you can call // from within the loaded index.html javascript Ti.App.addEventListener('helloWorld', function(passedData) { // Pass data to the webView webView.evalJS("alert(unescape('"+passedData.data"+'))"); });
index.html - Javascript <script> // This is how you trigger the event listener created above // from within javascript inside index.html Ti.App.fireEvent('helloWorld', { data : escape("Hello World") } ); </script>
I've added in the escape function because it helps you pass serialized objects around without fear of syntax errors.
-
Hi!
WebViews are able to listen to and fire Titanium events as well.
We use this in our word game Golingo, and wrap the event-handling to get transparent callbacks. The code is as follows:var Test = { name: 'test', init: function(){ this.proxiedHandleEvents = $.proxy(this.handleEvents, this); Ti.App.addEventListener('app', this.proxiedHandleEvents); }, // Event cannon with callback fix. fire: function(opts){ // If we're providing a callback, save a reference to it here // to be able to call it when the response returns from the other side. if (opts.func && opts.callback) { var c = ++this.callbackCounter; this.callbacks[c] = opts.callback; // Must remap the callback to a callback id since we cannot // pass functions between the native context and the webview context opts.callback = c; } opts.from = this.name; Ti.App.fireEvent(opts.to, opts); }, // Event delegator handleEvents: function(e){ // If the event object has a 'func' property, // and that property is a function available in our singleton - call it. if (typeof this[e.func] === 'function') { // If a callback id is provided, the caller is waiting for a response. // Overwrite the callback id with a replier function responding with that id. // When our referenced function is done, it passes its result to the replier // function, which makes sure the callback on the other side is passed that result. if (e.callback) { var c = e.callback, self = this, from = e.from; e.callback = function(data){ self.fire({ data: data, to: from, // Return to sender callback: c // Call the callback with this id on the other side }); }; } if (!e.data) { e.data = {}; } // Call the specified function this[e.func](e); } // Was it a callback - eg a response from the other side? else if (e.callback && this.callbacks[e.callback]) { // Execute the correct callback and pass it the result object this.callbacks[e.callback](e); delete this.callbacks[e.callback]; } }, checkWords: function(words){ this.fire({ to: 'app', func: 'saveHighscore', data: { words: words }, callback: function(e){ alert("We found " + e.data.correctWords.length + " correct words"); } }); } }; Test.init(); Test.checkWords(['hi', 'ho', 'foo']);
You use this pattern both in the native part and in the webview.
/Jacob
-
I've spent hours fiddling with this, and Justin's method above is the only one I've been able to make work. There are a couple of things I had to change, though: first, there's a typo with the quote/plus sign reversed in the unescape call, in case you just want to paste this in and test it. Second, I had to put the fireEvent call in an onload function within the web view, instead of just a head script.
It drives me crazy that the webView.fireEvent function doesn't work at all, even though it's in the API doc. Eval is bad! No one should be forced to use eval!
-
hey Jacob,
is it possible for you to break your example down into as simple "hello world" function as possible?
Its hard to destinguish between your application specific code and the generic transport mechanism.
Thx very much for your post :)
-
Can I do this with a html file that is not located in the phone? Hosted in a server?
So the WebView would have a "url" parameter like this:
Var webView = Ti.UI.createWebView({url:'http://www.mysite.com/index.html'});
And then fireEvent on my server?
Tried without success.
-
Something I noticed (on iOS at least), is that the <body> tags in your webView's html must be wrapped in an <html> tag otherwise the Ti.App.fireEvent isn't picked up by app.js
-
The official way to go, if you're working with a REMOTE page, is to set up a listener on the webview for the 'load' event (to make sure you don't kick in too early), and then to fire an evalJS command which retrieves data from the webview.
If you are waiting for a specific event to occur, you can't add an event listener either to the webview or to the webpage document. You can set an interval in Titanium which executes evalJS every second (or whatever) and then wait for the result to change to whatever value you were waiting for.
webview.addEventListener('load',function(e) { //EvalJS executes the string as Javascript inside the webpage and //returns the value to the Titanium context. var checkForAnswer = setInterval(function(){ var evaluateThis = "document.cookie"; var result = webview.evalJS(evaluateThis);//.split(";"); Ti.API.debug("EVALJS" + result + " " + result.length) },1000) });
In my case, we are using a webpage inside a WebView for user registration and login. So the webpage being shown is our own creation. Thus, as soon as our webpage has connected to the server and received a response like " Login ok", the webpage javascript can set a local variable, and the Titanium interval function can check for changes to that value.
-
is there a way like the native android webview support where you can send data back to the webview (Android natively supports JavaScriptInterfaces whic accomplish to and frp communication between webview and native)
-
it's easy to pass data from js to html by when u r setting url 4 webview give it parameter and handle it in html file by java script