7

I tried to create a simple example of callback from Javascript to Java, based on the last example in WebEngine's javadoc (Calling back to Java from JavaScript). But when I click the link in the WebView, the Java method is not called and the page disappears.

public class TestOnClick extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        try {
            final WebView webView = new WebView();
            final WebEngine webEngine = webView.getEngine();

            Scene scene = new Scene(webView);

            stage.setScene(scene);
            stage.setWidth(1200);
            stage.setHeight(600);
            stage.show();

            String webPage = "<html>\n"
                    + "    <body>\n"
                    + "        <a href=\"\" onclick=\"app.onClick()\">Click here</a>\n"
                    + "    </body>\n"
                    + "</html>";

            System.out.println(webPage);

            webView.getEngine().loadContent(webPage);

            JSObject window = (JSObject) webEngine.executeScript("window");
            window.setMember("app", new JavaApp());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        launch(args);
    }

    public static class JavaApp {

        public void onClick() {
            System.out.println("Clicked");
        }
    }
}

Note: I don't see any exceptions being thrown in the WebView when monitoring the load worker with webView.getEngine().getLoadWorker().exceptionProperty().addListener(...).

1
  • Note for readers: Starting from 2.2.5 the bridge class (JavaApp in this case) must be declared public. Commented Nov 30, 2016 at 19:52

1 Answer 1

7

You are trying to access webview DOM model before it was created.

Wrap your JavaApp related code to the page load listener to achieve your goal:

webEngine.getLoadWorker().stateProperty().addListener(new ChangeListener<Worker.State>() {
    @Override
    public void changed(ObservableValue<? extends State> ov, State t, State t1) {
        if (t1 == Worker.State.SUCCEEDED) {
            JSObject window = (JSObject) webEngine.executeScript("window");
            window.setMember("app", new JavaApp());
        }
    }
});
Sign up to request clarification or add additional context in comments.

2 Comments

This apporach introduces a race condition if loaded page needs to access some application API at startup, because page JavaScript is executed before RUNNING -> SUCCEEDED transition happens.
to solve this classic problem of concurrent access you can use any standard approaches: e.g. wait in js till variable app is initialised.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.