javajavafxjavafx-webengine

JSException in Javafx webview


I'm getting some weird behaviour that I don't understand. I have a class MonologueTab:

public final class MonologueTab extends VBox{
    private MonologueNode node;
    WebView webView;
    WebEngine webEngine;

    public MonologueTab(){
        this.node = Game.getInstance().getMonologueDatabase().getMonologueNode();
        webView = new WebView();
        webEngine = webView.getEngine();
        createGui();
    }

    public void createGui(){

        Label textLabel = new Label ();
        textLabel.setGraphic(webView);
        textLabel.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
        webEngine.loadContent(node.getNextLine());
        this.getChildren().add(textLabel);
        textLabel.setOnMouseClicked((MouseEvent event) -> {
            String nextLine = node.getNextLine();
            if (nextLine!=null){
                webEngine.executeScript("document.getElementById('content').insertAdjacentHTML( 'beforeend'," + nextLine + ");");
                webEngine.executeScript("window.scrollTo(0, document.body.scrollHeight);");
            }
            else{
                EventManager.getInstance().notifyObserver("end" + node.getStartTrigger());
            }
        });
    }
}

that works as expected. But when I try to port basically the same code in to a new class DialogueTab:

public final class DialogueTab extends VBox implements EventObserver{
    WebView webView;
    WebEngine webEngine;

    public DialogueTab(){
        webView = new WebView();
        webEngine = webView.getEngine();
        EventManager.getInstance().addObserver(this);
        createGui();
    }

    public void createGui(){
        this.getChildren().removeAll(this.getChildren());
        Label conversation = new Label();
        conversation.setGraphic(webView);
        conversation.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
        webEngine.loadContent("<body><b>Available Conversations</b><br><div id='content'></div></body>");                
        this.getChildren().add(conversation);
        for (Person p: Game.getInstance().getPeopleAt()){
            webEngine.executeScript("document.getElementById('content').insertAdjacentHTML('beforeend', " + p.getShortDesc() + ");");
        //some irrelevance removed
        }
    }

It's throwing a: netscape.javascript.JSException: TypeError: null is not an object (evaluating 'document.getElementById('content').insertAdjacentHTML')

Now, I'm assuming that this is related to the issue here but I don't understand why it's working fine in one place but not in another.


Solution

  • I think why the first example works is because the scripts are only executed upon mouseclick (by which time the page should be fully loaded); While the second example execute the scripts direcly after it has requested to start loading (which is so fast after starting that it can't possibly be finnished loading).

    As for the solution, you provided the answer yourself in the post you linked. If you need any further explanation, feel free to ask.