This discussion is archived
6 Replies Latest reply: Mar 27, 2013 11:53 AM by 995198 RSS

Submiting HTML Forms with JavaFX Webview

995198 Newbie
Currently Being Moderated
I've long been searching for a good web robot framework. And I also need a gui for my robot.

So w/ the advent of JAVAFX Webengine it seemed my needs have been met finally. Specially because on the webview tutorial here , Alla Redko says: "+It supports user interaction such as navigating links *and submitting HTML forms*+".

But after looking at the api it doesn't seem that webengine supports submiting forms, only loading pages w/ the load() method. I guess I could populate the form fields and submit them w/ executeScript() but that's just sloppy.

Is there a way to actually submit forms w/ webengine? Are there plans to implement this feature, analogous to the load() method?

Thanks,
JC
  • 1. Re: Submiting HTML Forms with JavaFX Webview
    peterz Newbie
    Currently Being Moderated
    Not yet. Do you need some method like post(String url, String formData) ?
  • 2. Re: Submiting HTML Forms with JavaFX Webview
    995198 Newbie
    Currently Being Moderated
    I need the ability to find certain form fields, populate them (or check/select them), then submit the form along w/ all other hidden inputs that came w/ the page.

    tks
  • 3. Re: Submiting HTML Forms with JavaFX Webview
    James_D Guru
    Currently Being Moderated
    I'm not a JavaScript expert, but JavaScript would be a way to do all of these things. The WebEngine defines an executeScript(...) method which you can use to execute JavaScript in the context of a loaded document.

    You could also, I think, do the first step ("find certain form fields") by accessing the document model with WebEngine.getDocument().
  • 4. Re: Submiting HTML Forms with JavaFX Webview
    995198 Newbie
    Currently Being Moderated
    Yea, as I mentioned in the first post, I could do all that w/ JS but it's just sloppy, since I'm using Java language, not JS.

    The finding certain fields part is easy w/ the Document model and xpath, it's the populating the fields and submiting the form along w/ its hidden input fields that is the missing part.

    Does anyone know if these things are planned for the future of Webview/Webengine?

    Tks
  • 5. Re: Submiting HTML Forms with JavaFX Webview
    jsmith Guru
    Currently Being Moderated
    Yea, as I mentioned in the first post, I could do all that w/ JS but it's just sloppy, since I'm using Java language, not JS.
    The finding certain fields part is easy w/ the Document model and xpath, it's the populating the fields and submiting the form along w/ its hidden input fields that is the missing part.
    Does anyone know if these things are planned for the future of Webview/Webengine?
    You can already do this in Java today using the existing APIs if you so wished.
    import javafx.application.Application;
    import javafx.beans.property.*;
    import javafx.beans.value.*;
    import javafx.event.ActionEvent;
    import javafx.event.EventHandler;
    import javafx.scene.Scene;
    import javafx.scene.control.*;
    import javafx.scene.layout.*;
    import javafx.scene.web.*;
    import javafx.stage.Stage;
    import org.w3c.dom.*;
    import org.w3c.dom.html.*;
     
    public class WebViewFormPost extends Application {
      public static void main(String[] args) { launch(args); }
    
      @Override public void start(Stage stage) {
        final TextField fxUsername = new TextField();
        final TextField fxPassword = new PasswordField();
        
        final BooleanProperty loginAttempted = new SimpleBooleanProperty(false);
        
        final WebView webView = new WebView();
        final WebEngine engine = webView.getEngine();
        engine.documentProperty().addListener(new ChangeListener<Document>() {
          @Override public void changed(ObservableValue<? extends Document> ov, Document oldDoc, Document doc) {
            if (doc != null && !loginAttempted.get()) {
              if (doc.getElementsByTagName("form").getLength() > 0) {
                HTMLFormElement form = (HTMLFormElement) doc.getElementsByTagName("form").item(0);
                if ("/oam/server/sso/auth_cred_submit".equals(form.getAttribute("action"))) {
                  HTMLInputElement username = null;
                  HTMLInputElement password = null;
                  NodeList nodes = form.getElementsByTagName("input");
                  for (int i = 0; i < nodes.getLength(); i++) {
                    HTMLInputElement input = (HTMLInputElement) nodes.item(i);
                    switch (input.getName()) {
                      case "ssousername":
                        username = input;
                        break;
                      case "password":
                        password = input;
                        break;
                    }
                  }
                  
                  if (username != null && password != null) {
                    loginAttempted.set(true);
                    username.setValue(fxUsername.getText());
                    password.setValue(fxPassword.getText());
                    form.submit();
                    System.out.println("Submitted login for user: " + username);
                  }  
                }  
              }
            }
          }
        });
        engine.getLoadWorker().exceptionProperty().addListener(new ChangeListener<Throwable>() {
          @Override public void changed(ObservableValue<? extends Throwable> ov, Throwable oldException, Throwable exception) {
            System.out.println("Load Exception: " + exception);
          }
        });
    
        GridPane inputGrid = new GridPane();
        inputGrid.setHgap(10);
        inputGrid.setVgap(10);
        inputGrid.addRow(0, new Label("Username: "), fxUsername);
        inputGrid.addRow(0, new Label("Password: "), fxPassword);
        
        Button fxLoginButton = new Button("Login to Oracle Forums");
        fxLoginButton.setOnAction(new EventHandler<ActionEvent>() {
          @Override public void handle(ActionEvent t) {
            if (notEmpty(fxPassword.getText()) && notEmpty(fxPassword.getText())) {
              loginAttempted.set(false);
              engine.load("https://forums.oracle.com/forums/login!withRedirect.jspa");
            }  
          }
        });
        
        final VBox layout = new VBox(10);
        layout.setStyle("-fx-background-color: cornsilk; -fx-padding: 10;");
        layout.getChildren().addAll(
          new Label("Enter your Oracle Web Account credentials"), 
          inputGrid, 
          fxLoginButton, 
          webView
        );
        
        stage.setScene(new Scene(layout));
        stage.show();
      }
    
      private boolean notEmpty(String s) {
        return s != null && !"".equals(s);
      }
    }
    Personally, I think using JavaScript via engine.executeScript calls in combination with jquery might be a less messy solution (as I don't like writing against the raw dom apis), but I understand that there are valid reasons why you might prefer to use a Java only solution.
    https://gist.github.com/jewelsea/3077942 "Embeds jQuery in a document loaded into a WebView."
  • 6. Re: Submiting HTML Forms with JavaFX Webview
    995198 Newbie
    Currently Being Moderated
    This is actually a pretty good solution.. I didn't know about this implementation in the org.w3c.dom.html package that already comes w/ Java. And by the way it's not part of the standard java7 javadoc. The javadoc is in a different url.

    Just a remark: adding a listener to the doc change seems to be inefficient since as every new element is added to the DOM, it'll trigger a new call to this listener, and you'll only be returning from calls until the form element is completed. A better approach is the setOnSucceeded property of the WebEngine.getLoadWorker. That's what I'll try.

    Thanks!
    jsmith wrote:
    Yea, as I mentioned in the first post, I could do all that w/ JS but it's just sloppy, since I'm using Java language, not JS.
    The finding certain fields part is easy w/ the Document model and xpath, it's the populating the fields and submiting the form along w/ its hidden input fields that is the missing part.
    Does anyone know if these things are planned for the future of Webview/Webengine?
    You can already do this in Java today using the existing APIs if you so wished.
    import javafx.application.Application;
    import javafx.beans.property.*;
    import javafx.beans.value.*;
    import javafx.event.ActionEvent;
    import javafx.event.EventHandler;
    import javafx.scene.Scene;
    import javafx.scene.control.*;
    import javafx.scene.layout.*;
    import javafx.scene.web.*;
    import javafx.stage.Stage;
    import org.w3c.dom.*;
    import org.w3c.dom.html.*;
    
    public class WebViewFormPost extends Application {
    public static void main(String[] args) { launch(args); }
    
    @Override public void start(Stage stage) {
    final TextField fxUsername = new TextField();
    final TextField fxPassword = new PasswordField();
    
    final BooleanProperty loginAttempted = new SimpleBooleanProperty(false);
    
    final WebView webView = new WebView();
    final WebEngine engine = webView.getEngine();
    engine.documentProperty().addListener(new ChangeListener<Document>() {
    @Override public void changed(ObservableValue<? extends Document> ov, Document oldDoc, Document doc) {
    if (doc != null && !loginAttempted.get()) {
    if (doc.getElementsByTagName("form").getLength() > 0) {
    HTMLFormElement form = (HTMLFormElement) doc.getElementsByTagName("form").item(0);
    if ("/oam/server/sso/auth_cred_submit".equals(form.getAttribute("action"))) {
    HTMLInputElement username = null;
    HTMLInputElement password = null;
    NodeList nodes = form.getElementsByTagName("input");
    for (int i = 0; i < nodes.getLength(); i++) {
    HTMLInputElement input = (HTMLInputElement) nodes.item(i);
    switch (input.getName()) {
    case "ssousername":
    username = input;
    break;
    case "password":
    password = input;
    break;
    }
    }
    
    if (username != null && password != null) {
    loginAttempted.set(true);
    username.setValue(fxUsername.getText());
    password.setValue(fxPassword.getText());
    form.submit();
    System.out.println("Submitted login for user: " + username);
    }  
    }  
    }
    }
    }
    });
    engine.getLoadWorker().exceptionProperty().addListener(new ChangeListener<Throwable>() {
    @Override public void changed(ObservableValue<? extends Throwable> ov, Throwable oldException, Throwable exception) {
    System.out.println("Load Exception: " + exception);
    }
    });
    
    GridPane inputGrid = new GridPane();
    inputGrid.setHgap(10);
    inputGrid.setVgap(10);
    inputGrid.addRow(0, new Label("Username: "), fxUsername);
    inputGrid.addRow(0, new Label("Password: "), fxPassword);
    
    Button fxLoginButton = new Button("Login to Oracle Forums");
    fxLoginButton.setOnAction(new EventHandler<ActionEvent>() {
    @Override public void handle(ActionEvent t) {
    if (notEmpty(fxPassword.getText()) && notEmpty(fxPassword.getText())) {
    loginAttempted.set(false);
    engine.load("https://forums.oracle.com/forums/login!withRedirect.jspa");
    }  
    }
    });
    
    final VBox layout = new VBox(10);
    layout.setStyle("-fx-background-color: cornsilk; -fx-padding: 10;");
    layout.getChildren().addAll(
    new Label("Enter your Oracle Web Account credentials"), 
    inputGrid, 
    fxLoginButton, 
    webView
    );
    
    stage.setScene(new Scene(layout));
    stage.show();
    }
    
    private boolean notEmpty(String s) {
    return s != null && !"".equals(s);
    }
    }
    Personally, I think using JavaScript via engine.executeScript calls in combination with jquery might be a less messy solution (as I don't like writing against the raw dom apis), but I understand that there are valid reasons why you might prefer to use a Java only solution.
    https://gist.github.com/jewelsea/3077942 "Embeds jQuery in a document loaded into a WebView."
    Edited by: ttilt on 27/03/2013 11:47

Legend

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