title: JavaFX WebView - Communicating between Java and Javascript after page redirection
body: <p>I'm developing a JavaFX WebView application to let users navigate through an existing third-party website.</p>
  
  <p>The pages on the site rely on $(document).ready() style functions in order to work properly and my Java Bridge object should be visible to the JavaScript side by then.</p>
  
  <p>While my code works as expected for the first page loaded, for any other page the user navigates to the Bridge object doesn't seem to get registered until way after the JavaScript of the page has finished executing, likely throwing a bunch of 'undefined' errors.</p>
  
  <p>Here's a quick project I put together demonstrating what I'm trying to do:</p>
  
  <p>WebViewTest.java</p>
  
  <pre><code>import javafx.application.Application;
  import javafx.scene.Scene;
  import javafx.scene.layout.StackPane;
  import javafx.scene.web.WebEngine;
  import javafx.scene.web.WebView;
  import javafx.stage.Stage;
  import netscape.javascript.JSObject;
  
  public class WebViewTest extends Application {
  
      @Override
      public void start(Stage stage) {
          try {
              WebView web = new WebView();
              WebEngine engine = web.getEngine();
              Bridge bridge = new Bridge();
  
              engine.getLoadWorker().stateProperty().addListener((observable, oldState, newState) -&gt; {
                  switch (newState) {
                      //Doing this in any state other than SUCCEEDED doesn't seem to do anything.
                      case SUCCEEDED:
                          JSObject jsobj = (JSObject) engine.executeScript("window");
                          jsobj.setMember("JavaBridge", bridge);
                          break;
                  }
              });
  
              StackPane root = new StackPane();
              root.getChildren().add(web);
  
              Scene scene = new Scene(root, 800, 600);
  
              stage.setScene(scene);
              stage.show();
  
              //Adding these two lines gets the very first page loaded to work as expected.
              JSObject jsobj = (JSObject) engine.executeScript("window");
              jsobj.setMember("JavaBridge", bridge);
  
              engine.load("http://localhost/JavaFXTest/first.html");
          } catch (Exception e) {
              e.printStackTrace();
          }
      }
  
      public static void main(String[] args) {
          launch(args);
      }
  }
  </code></pre>
  
  <p>Bridge.java</p>
  
  <pre><code>public class Bridge {
      public void print(String msg) {
          System.out.println("Invoked from JavaScript: " + msg);
      }
  }
  </code></pre>
  
  <p>first.html</p>
  
  <pre><code>&lt;html&gt;
      &lt;head&gt;
          &lt;script src="jquery-1.12.4.min.js"&gt;&lt;/script&gt;
      &lt;/head&gt;
      &lt;body&gt;
          &lt;script&gt;
              JavaBridge.print('FIRST');
  
              $(document).ready(function(){
                  JavaBridge.print('FIRST READY');
              });
          &lt;/script&gt;
  
          &lt;h1&gt;first&lt;/h1&gt;
          &lt;a href="second.html"&gt;Second&lt;/a&gt;
  
          &lt;button onclick="JavaBridge.print('FIRST CLICK');"&gt;Click!&lt;/button&gt;
      &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p>second.html</p>
  
  <pre><code>&lt;html&gt;
      &lt;head&gt;
          &lt;script src="jquery-1.12.4.min.js"&gt;&lt;/script&gt;
      &lt;/head&gt;
      &lt;body&gt;
          &lt;script&gt;
              JavaBridge.print('SECOND');
  
              $(document).ready(function(){
                  JavaBridge.print('SECOND READY');
              });
          &lt;/script&gt;
  
          &lt;h1&gt;second&lt;/h1&gt;
          &lt;a href="first.html"&gt;First&lt;/a&gt;
  
          &lt;button onclick="JavaBridge.print('SECOND CLICK');"&gt;Click!&lt;/button&gt;
      &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p>Running the application initially outputs, as desired:</p>
  
  <pre><code>Invoked from JavaScript: FIRST
  Invoked from JavaScript: FIRST READY
  </code></pre>
  
  <p>However, after clicking the link to go to the second page, neither of those lines are printed, yet clicking on the button works as intended:</p>
  
  <pre><code>Invoked from JavaScript: SECOND CLICK
  </code></pre>
  
  <p>And if we click the first link to go back to the first page, the lines are not printed either, but clicking works.</p>
  
  <p>The only workaround I've been able to come up with so far is completely discarding my current WebView object and creating a new one anytime a location listener fires, as subsequent calls to engine.load() don't seem to help either. Nevertheless, doing that kinda breaks things if there are sessions or post parameters involved...</p>
  
  <p>I have been struggling with this for a few days and I'm pretty much stuck now, so if anyone can point out if I'm missing something, I'd appreciate it.</p>