4

I'm adding a script tag to a web page once it's fully loaded in a WebEngineView, but it's silently failing somehow.

I inject the script by invoking webview.runJavaScript with this code:

var s = document.createElement('script');
s.src = "qrc:/jquery-2.1.4.min.js";
document.body.appendChild(s);

That's perfectly standard and to a certain extent it works as expected, i.e., if I view the html source of the page, the script tag has indeed been appended to the body.

The problem is that the script isn't being downloaded, or isn't being evaluated, or something. All I know is in the above example the jQuery functions aren't available. If I load a small JavaScript test file with one global variable, that variable's not available either. Changing the url to http instead of qrc and pointing it to a web server makes no difference.

Injecting an img tag works fine; the image is loaded and displayed.

But JavaScript is broken somehow. Does anyone know how to fix this?

BaCaRoZzo
  • 7,502
  • 6
  • 51
  • 82
WaltPurvis
  • 1,510
  • 12
  • 14
  • 2
    It looks like the problem is not with the script itself but with what should run the script, is it linked to a button or some other event? – Marco Jun 29 '15 at 22:26
  • Thank you for this comment — it sent me down the right path to find a solution. The script was being run from the webview's signal that the page had finished loading. When I broke the script up into three discrete pieces and attached them to three different buttons, it worked, which made me realize it was a problem with asynchronous calls / functions executing too fast. That guided me to the solution I posted below. – WaltPurvis Jun 30 '15 at 14:58

1 Answers1

2

The problem had to do with the asynchronous nature of QML and JavaScript.

I was inserting a script tag to inject jQuery, and then I was calling a function to de-conflict my inserted version of jQuery from whatever version of jQuery might already be in the original page.

But I believe the webview had not finished parsing the inserted jQuery library before my de-conflicting function was called, so it failed. (I'm not very experienced with browser programming or I might have suspected this from the beginning.)

The solution was to insert a script tag with a small bit of JavaScript that inserts jQuery and then sets a timeout to wait 200ms before calling the de-conflict function. Like so:

function insertAuhJQuery(){
var s = document.createElement("script");
s.src = "qrc:/jquery-2.1.4.min.js";
document.body.appendChild(s);
window.setTimeout(deConflictJQuery, 200);
}

function deConflictJQuery(){
auh = {};
auh.$ = jQuery.noConflict(true);
}

insertAuhJQuery()

That works reliably and is acceptable for my purpose.

WaltPurvis
  • 1,510
  • 12
  • 14