This discussion is archived
2 Replies Latest reply: Nov 29, 2012 6:07 AM by PatrickMartin RSS

Calling javascript from JavaFX

PatrickMartin Newbie
Currently Being Moderated
This is well documented, yet I am having trouble communicating with JavaScript from JavaFX. The relevant snippet is:
WebView wv = new WebView();
WebEngine we = wv.getEngine();

String content = FileUtils.readFileToString(new File("test.html"));
we.loadContent(content);

we.executeScript("changeBackground();");
Which reads the following content:

test.html:
<html>
<body>
<script type="text/javascript">
document.bgColor = "#cccccc";
function changeBackground()
{
  document.bgColor = "#ff0000";
}
</script>
</body>
</html>
giving error:
netscape.javascript.JSException: ReferenceError: Can't find variable: changeBackground
     at com.sun.webpane.platform.WebPage.twkExecuteScript(Native Method)
     at com.sun.webpane.platform.WebPage.executeScript(WebPage.java:1438)
     at javafx.scene.web.WebEngine.executeScript(WebEngine.java:811)
     at com.javainc.tmi.WebTest.init(WebTest.java:30)
     at com.javainc.tmi.WebTest.start(WebTest.java:44)
     at com.sun.javafx.application.LauncherImpl$5.run(LauncherImpl.java:319)
     at com.sun.javafx.application.PlatformImpl$5.run(PlatformImpl.java:206)
     at com.sun.javafx.application.PlatformImpl$4.run(PlatformImpl.java:173)
     at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
     at com.sun.glass.ui.win.WinApplication.access$100(WinApplication.java:29)
     at com.sun.glass.ui.win.WinApplication$3$1.run(WinApplication.java:73)
     at java.lang.Thread.run(Unknown Source)
I've tried it without the semi colons at the end as well as every permutation I can think of.

When I remove the executeScript code, the webview displays and turns the screen grey as it should.

Is this a bug or am I missing something obvious?

I am using 64 bit jdk1.7.0_09 on Windows 7.

- Pat
  • 1. Re: Calling javascript from JavaFX
    jsmith Guru
    Currently Being Moderated
    The document loads into the WebEngine asynchronously.
    You have to wait for it to finish loading before you try to run a script on it.

    For example, you can listen to the document property:
    we.documentProperty().addListener(new ChangeListener<Document>() {
      @Override public void changed(ObservableValue<? extends Document> observableValue, Document document, Document newDoc) {
        if (newDoc != null) {
          we.documentProperty().removeListener(this);
          we.executeScript("changeBackground();");
        }
      }
    });
    Or you could grab the WebEngine's LoadWorker and listen for it's state change.

    Some shorthand where you provide the load or loadContent method with a CallBack to be executed in the event of a successful page load might be convenient, so you could file a request in jira if you'd like that, but the listener methods work ok too.
    -------
    Full executable example (using your test.html):
    import javafx.application.Application;
    import javafx.beans.value.ChangeListener;
    import javafx.beans.value.ObservableValue;
    import javafx.scene.Scene;
    import javafx.scene.web.WebEngine;
    import javafx.scene.web.WebView;
    import javafx.stage.Stage;
    import org.w3c.dom.Document;
    
    import java.io.*;
    
    public class ScriptExecutive extends Application {
    
      public static void main(String[] args) { launch(args); }
    
      @Override public void start(final Stage stage) {
        final WebView wv = new WebView();
        final WebEngine we = wv.getEngine();
    
        we.documentProperty().addListener(new ChangeListener<Document>() {
          @Override public void changed(ObservableValue<? extends Document> observableValue, Document document, Document newDoc) {
            if (newDoc != null) {
              we.documentProperty().removeListener(this);
              we.executeScript("changeBackground();");
            }
          }
        });
    
        String content = FileUtils.readFileToString(new File("test.html"));
        we.loadContent(content);
    
        stage.setScene(new Scene(wv));
        stage.show();
      }
    
      static class FileUtils {
        public static String readFileToString(File file) {
          try {
            StringBuilder builder = new StringBuilder();
    
            String line;
            BufferedReader reader = new BufferedReader(new FileReader(file));
            while ((line = reader.readLine()) != null) builder.append(line);
    
            return builder.toString();
          } catch (FileNotFoundException e) {
            System.out.println("Cannot find: " + file);
            return "";
          } catch (IOException e) {
            System.out.println("Oh snap, it broke: " + e);
            return "";
          }
        }
      }
    }
  • 2. Re: Calling javascript from JavaFX
    PatrickMartin Newbie
    Currently Being Moderated
    Thanks John!

    Moving the script execution to correspond with a button push handled my particular situation.

    - Pat

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points