JavaFX webview window.onload started before loadworker succeeds
I am using JavaFX webview in my application. With the following code I am setting the element after the page has loaded
webEngine.getLoadWorker().stateProperty().addListener(new ChangeListener<Worker.State>() {
@Override
public void changed(ObservableValue ov, Worker.State oldState, Worker.State newState) {
if (newState == Worker.State.SUCCEEDED) {
JSObject window = (JSObject) webEngine.executeScript("window");
window.setMember("mymember", new JavaScriptBridge(this));
}
}
});
Now in javascript I can call mymember.doSomething()
eg. when i click the button and it succeeds, but if i add the following code to html
<script>
function startup() {
mymember.doSomething();
}
window.onload=startup;
</script>
It does not run automatically on page load. Seems to be window.onload
running before notification LoadWorker
. So it mymember
's not installed yet. But on the other hand, I cannot install mymember
before the html has been loaded, right?
Any idea when I need to install mymember
so that it is ready when executed window.onload
?
Thank!
source to share
It may be too late to answer this problem, but after answering this question, I was trying to find the reason why it executeScript
should be after the web page has fully loaded.
So, I did this test:
public class EarlyWebEngineTest extends Application {
@Override
public void start(Stage stage) {
final WebView webView = new WebView();
final WebEngine webEngine = webView.getEngine();
// Early call of executeScript to get a JavaScript object, a proxy for the
// Java object to be accessed on the JavaScript environment
JSObject window = (JSObject) webEngine.executeScript("window");
window.setMember("app", new JavaApplication());
webEngine.getLoadWorker().stateProperty().addListener((ov,oldState,newState)->{
if(newState==State.SCHEDULED){
System.out.println("state: scheduled");
} else if(newState==State.RUNNING){
System.out.println("state: running");
} else if(newState==State.SUCCEEDED){
System.out.println("state: succeeded");
}
});
Button button=new Button("Load Content");
button.setOnAction(e->webEngine.loadContent("<html>"
+ " <script>function initialize() {"
+ " var nameVar = \"This is a JS var\"; "
+ " app.callJavascript(nameVar);"
+ "} </script>"
+ " <body onLoad=\"initialize()\">Hi, this is a test!</body>"
+ "</html>"));
VBox vbox = new VBox(10,button,webView);
Scene scene = new Scene(vbox,400,300);
stage.setScene(scene);
stage.show();
}
public class JavaApplication {
public void callJavascript(String msg){
System.out.println("JS>> "+msg);
}
}
public static void main(String[] args) {
launch(args);
}
}
The content doesn't load until the button is clicked, but we've already created a JavaScript object in the browser.
There is nothing on the output console before the button is pressed. But if we click the button ... this is the output:
state: scheduled
state: running
JS>> This is a JS var
state: succeeded
As we can see, the Java object is efficiently passed to the script before the latter is executed, and app.callJavascript
successfully invoked while the content is loading.
Note that for the general purpose of accessing the loaded DOM it is generally a good idea to use a normal call executeScript
after call State.SUCCEEDED
.
source to share