The RequestContext
utility class provides an easy way to execute any JavaScript code after the current AJAX request completes. The JavaScript block has to be coded in Java and can be executed by passing it to the execute()
method. An alternative approach would be to update a script block on a page and trigger the script execution manually. In this case, the JavaScript block is coded directly into a page.
In this recipe, we will see both solutions for JavaScript execution. For this purpose, we will develop a menu
component and toggle the enabling/disabling of menu items with two command buttons. The first command button should toggle enabling/disabling with the server-side approach and the second one with the client-side approach.
Let's write a p:menu
tag with three menu items. We also need two p:commandButton
tags with appropriate action listeners:
<h:outputText id="indicator" value="Enabled? - #{javaScriptExecBean.enabled}"/> <p:menu id="menu" style="margin:20px 0 10px 0;"> <p:submenu label="JavaScript Libraries"> <p:menuitem value="jQuery" url="http://jquery.com"/> <p:menuitem value="Yahoo UI" url="http://yuilibrary.com"/> <p:menuitem value="Prototype" url="http://prototypejs.org"/> </p:submenu> </p:menu> <p:commandButton id="toggle1" value="Toggle Menuitems (server-side)" process="@this" update="indicator" actionListener="#{javaScriptExecBean.toggleMenuitems}"/> <p:commandButton id="toggle2" value="Toggle Menuitems (client-side)" process="@this" update="indicator toggleScriptWrapper" actionListener="#{javaScriptExecBean.toggleEnabled}"/> <h:panelGroup id="toggleScriptWrapper"> <script type="text/javascript"> if (#{facesContext.partialViewContext.ajaxRequest}) { $('#menu').find('a').each(function() { var $this = $(this); if ($this.attr('href')) { // disable item $this.attr('data-href', $this.attr('href')) .removeAttr('href') .addClass('ui-state-disabled'), } else { // enable item $this.attr('href', $this.attr('data-href')) .removeAttr('data-href') .removeClass('ui-state-disabled'), } }); } </script> </h:panelGroup>
The panelGroup
component with the toggleScriptWrapper
ID contains the script logic that is executed after each update on this panelGroup
component. The bean packs the same logic in a String
variable script
and executes it with requestContext.execute(script)
:
@Named @ViewScoped public class JavaScriptExecBean implements Serializable { private boolean enabled = true; public void toggleMenuitems(ActionEvent ae) { RequestContext requestContext = RequestContext.getCurrentInstance(); String script; if (enabled) { script = "$('#menu a').each(function() {" + "$(this).attr('data-href', $(this).attr('href'))" + ".removeAttr('href')" + ".addClass('ui-state-disabled'),});"; } else { script = "$('#menu a').each(function() {" + "$(this).attr('href', $(this).attr('data-href'))" + ".removeAttr('data-href')" + ".removeClass('ui-state-disabled'),});"; } requestContext.execute(script); enabled = !enabled; } public void toggleEnabled(ActionEvent ae) { enabled = !enabled; } public boolean isEnabled() { return enabled; } }
The following screenshot shows what the disabled menu items look like:
Both client-side and server-side scripts implement the same logic. To disable a menu item, its URL has to be copied from the anchor's href
attribute to a data-href
attribute. The href
attribute should be removed then, and the link should be styled with a proper jQuery ThemeRoller class, ui-state-disabled
. This style class makes elements appear disabled. To enable a menu item, its URL has to be restored from the data-href
attribute and assigned to href
. The style class, ui-state-disabled
, should be removed.
Also, consider the if
statement with the EL expression, #{facesContext.partialViewContext.ajaxRequest}
. This statement prevents an initial script execution on page load (the GET
request).
This recipe is available in the demo web application on GitHub (https://github.com/ova2/primefaces-cookbook/tree/second-edition). Clone the project if you have not done it yet, explore the project structure, and build and deploy the WAR file on application servers compatible with Servlet 3.x, such as JBoss WildFly and Apache TomEE.
The showcase for the recipe is available at http://localhost:8080/pf-cookbook/views/chapter11/javaScriptExec.jsf
.