Vaadin: Executing custom JavaScript from a thread, or loading custom JavaScript functions into global scope

As you may know already, in Vaadin you can use com.vaadin.ui.JavaScript.getCurrent().execute(…) function to execute some custom JavaScript on the client browser.

  1. Executing custom JavaScript from a thread:
    The above works well as long as the JavaScript execute() method is being called on the main UI thread. However, if JavaScript.getCurrent().execute() is called from a background thread, the JavaScript won’t get executed until there is a periodic refresh of the UI, or there’s a UI event (triggered by the user, such as a mouse click somewhere). This can seem to cause erratic behavior, with the JavaScript executing at unpredictable times. (Side note: any Vaadin UI access/manipulation from a background thread needs to be done inside com.vaadin.UI.getCurrent().access(new Runnable() { … });, and also note that you want to do your time-consuming heavy lifting first (such as retrieving data from the back end) and then go into UI.getCurrent().access(…) to manipulate the UI).To get around this problem, simply use Vaadin Push. You’ll need to enable push if not already (see Vaadin documentation on how). Then depending on the push mode you’ve used (manual or automatic) you’ll either need to call com.vaadin.ui.UI.getCurrent().push() or not (for manual mode you’ll need to call the push() method, for automatic mode it will be called after the runnable you send to the UI.access(…) method finishes executing). So call get JavaScript.execute(…), and then UI.push() last. Example:

    new Thread() {
        public void run() {
            //some long running background work
                 UI.getCurrent.access(new Runnable() {
                public void run() {
                    JavaScript.getCurrent().execute("alert('Background Task Complete!');");
                                UI.getCurent().push();
                }
            });
        }
    }.start();
  2. Loading custom JavaScript functions into global scope:
    This is extremely useful so you can define a JavaScript function which you can use later from JavaScript.getCurrent().execute(…), such as inside an event (a button click, for example). However, the JavaScript function will need to be in the global scope by injecting it into thetag for the HTML page served by Vaadin. To do this, use the following code while your Vaadin view is being created, or is being enter()’ed.

    StringBuilder script = new StringBuilder(); script .append("var head = document.getElementsByTagName('head')[0];") .append("var script = document.createElement('script');") .append("script.content='function sayHello() { alert(\"Hello!\");}';") .append("head.appendChild(script);"); JavaScript.getCurrent().execute(script.toString());

    Note: as I mentioned, a JavaScript function can only be loaded this way when the view is being created, or in the view’s enter() method. To create a function this way AFTER the page is already loaded (such as through some event), you’ll need to use Vaadin Push, and call UI.getCurrent().push() after the JavaScript.getCurrent().execute() even though you’re not on a background thread.

  3. You can define a function in the script tag being created above, which can then be called later on through JavaScript.getCurrent().execute(“sayHello();”); perhaps inside a Vaadin button click listener.

Enjoy!

Leave a Reply

Your email address will not be published. Required fields are marked *