Execute JavaScript
webforJ runs on the server, but there are times you need to reach the client: scroll the window, focus a field, read a browser value, or call a method on a web component. The HasJsExecution interface provides that bridge. It's implemented at two levels:
- The
Pageruns script in the context of the whole page. - An
Elementruns script scoped to a single client element.
Both expose the same three methods, so once you know the shapes below, they read the same whether you call them on Page or an Element.
Execution methods
Each level offers a synchronous method and two asynchronous ones. The difference is whether the calling thread waits and whether a result comes back.
-
executeJs(String script): runs the script synchronously. The executing thread is blocked until the client returns, which costs one server-to-client round trip. The result comes back as anObjectyou can cast and use in Java. -
executeJsAsync(String script): runs the script asynchronously and doesn't block the executing thread. It returns aPendingResultthat completes when the script finishes, so you can react to the result later. -
executeJsVoidAsync(String script): runs the script asynchronously and returns nothing to the server. Use it for fire-and-forget work where you don't need the result. Available since24.11.
Reach for executeJsVoidAsync by default when you are only causing a side effect on the client (scrolling, focusing, calling a method). Use executeJsAsync when you need the value but want to stay non-blocking, and reserve the synchronous executeJs for the rare case where you must have the result before the next line of Java runs, since it holds the thread for a full round trip.
Reading results
When a script returns a value, webforJ converts it to the matching Java type:
| JavaScript value | Java type |
|---|---|
| number | Integer, Long, or Double |
| string | String |
| boolean | Boolean |
null or undefined | null |
| any other type | its string representation |
Read values with executeJsAsync, which applies the conversion reliably. A returned number can arrive as Integer, Long, or Double, so read it through Number:
Page.getCurrent()
.executeJsAsync("return window.innerWidth;")
.thenAccept(result -> {
int width = ((Number) result).intValue();
// use width
});
The synchronous executeJs returns null when the execution context isn't ready, for example when it's called before the component is attached. Use executeJsAsync whenever you depend on the returned value, and avoid casting a synchronous result to a specific type.
App-level execution
Call the methods on Page when the script concerns the page as a whole rather than one component. Get the current page with Page.getCurrent().
A common case is scrolling back to the top after a route change. Nothing needs to come back, so executeJsVoidAsync fits:
Page.getCurrent().executeJsVoidAsync(
"window.scrollTo({ top: 0, behavior: 'smooth' });");
When you need a client value on the server, read it asynchronously and act on the result when it arrives:
Page.getCurrent()
.executeJsAsync("return navigator.language;")
.thenAccept(language -> {
// language is the browser locale, for example "en-US"
applyLocale(String.valueOf(language));
});
Use element-level execution when the script needs to act on a specific client element rather than the page as a whole.
In the demo below, selecting Copy link runs a script through Page with executeJsVoidAsync to write the invite link to the visitor's clipboard. Copying is a side effect with nothing to return, so the fire-and-forget method is the right fit.
Show Code
- ExecuteJavaScriptView.java
Element-level execution
Calling the same methods on an Element scopes the script to that element instead of the page. The return values and the synchronous and asynchronous behavior match the preceding page-level methods.
Element scripts queue until the element is attached to the DOM, then run, so you can call them during setup without waiting for attachment yourself.
Calling a function on an element
When you want to invoke a named client-side function rather than run a script string, Element offers a parallel set of methods. Instead of a script, you pass the function name and its arguments, which webforJ serializes and passes through. Two argument types are handled specially: this is replaced with the client element, and any Component argument is replaced with its client instance once attached.
These mirror the execute methods, differing only in whether the thread waits and whether a result returns:
-
callJsFunction(String name, Object... args): calls the function synchronously and returns its result as anObject. The executing thread blocks for one round trip. -
callJsFunctionAsync(String name, Object... args): calls the function asynchronously without blocking, returning aPendingResultthat completes with the function's result. Available since24.11. -
callJsFunctionVoidAsync(String name, Object... args): calls the function asynchronously and returns nothing to the server. Use it for fire-and-forget calls where you don't need the return value. Available since24.11.
Because the call waits for every Component argument to attach before running, a call that passes a component which never attaches never completes.
// Focus a web component's input by calling its client-side method
searchElement.callJsFunctionVoidAsync("focus");