This blogpost is inspired by the great work of Frank Nimphius ( Lot's of demos and a very good chapter in his book ) and a very nice blogpost of Chris how you can use hotkeys, to switch Tabs in UIShell.
Before you can start we need to add some context parameters to the web.xml
<context-param> <param-name>oracle.adf.view.rich.profiler.ENABLED</param-name> <param-value>true</param-value> </context-param> <context-param> <param-name>oracle.adf.view.rich.LOGGER_LEVEL</param-name> <param-value>ERROR</param-value> </context-param> <context-param> <param-name>oracle.adf.view.rich.LOG_WRITERS</param-name> <param-value>AdfConsoleLogWriter</param-value> </context-param> <context-param> <param-name>org.apache.myfaces.trinidad.DEBUG_JAVASCRIPT</param-name> <param-value>true</param-value> </context-param>I set the oracle.adf.view.rich.LOGGER_LEVEL to ERROR because the RC frameworks generates a lot of INFO messages, so you won't see your own log messages.
The oracle.adf.view.rich.LOG_WRITERS parameter enables the Javascript Logger popup window, when the firebug console is enabled then this popup won't launch and the messages will be seen in the firebug console window.
The org.apache.myfaces.trinidad.DEBUG_JAVASCRIPT will allow to debug a javascript file in the firebug debug console.
The next step is to create a javascript file and put this in a new folder in the Web Content folder of your web application.
To load the javascript files in your ADF Web Application you can use af:resource
<af:resource type="javascript" source="js/keys.js"/>
When you do this in the JSPX page then every page / region or fragment can call these javascript methods.
<?xml version='1.0' encoding='UTF-8'?> <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:af="http://xmlns.oracle.com/adf/faces/rich"> <jsp:directive.page contentType="text/html;charset=UTF-8"/> <f:view beforePhase="#{viewScope.HandleKeys.registerKeyboardMapping}"> <af:document id="document" title="Client Side"> <af:resource type="javascript" source="js/keys.js"/> <af:resource type="javascript" source="js/utils.js"/> <af:serverListener type="keyboardToServerNotify" method="#{viewScope.HandleKeys.handleKeyboardEvent}"/> <af:form id="f1"> <af:pageTemplate viewId="/oracle/ui/pattern/dynamicShell/dynamicTabShell.jspx" value="#{bindings.pageTemplateBinding}" id="pt1">
To call a javascript method from your JSF page you can use af:clientListener where you need to provide the method name and how it is activated.
<af:clientListener method="numbersOnly" type="keyDown"/>
Here an example of a javascript method
function numbersOnly(evt){ var _keyCode = evt.getKeyCode(); var _filterField = evt.getCurrentTarget(); var _oldValue = _filterField.getValue(); AdfLogger.LOGGER.logMessage(AdfLogger.ERROR, "key: "+_keyCode); //check for characters if (_keyCode > 64 && _keyCode < 91){ _filterField.setValue(_oldValue); evt.cancel(); } }In this code the AdfLogger.LOGGER.logMessage will log a message in the firebug console or logging popup.
ADF 11g has a very large Javascript API which you can use in your own Web Application, to see the API, click here.
You can also pass on data to the javascript method. You can use the af:clientAttribute for this with as value a text or an EL expression.
<af:panelHeader text="Tab Order" id="ph4"> <af:panelFormLayout id="pform" clientComponent="true"> <af:inputText id="it3" label="Tab 1"> <af:clientAttribute name="tabindex" value="1"/> <af:clientListener method="setTabIndex('1','4')" type="keyPress"/> </af:inputText> <af:inputText id="it4" label="Tab 3"> <af:clientAttribute name="tabindex" value="3"/> <af:clientListener method="setTabIndex('1','4')" type="keyPress"/> </af:inputText> <af:inputText id="it5" label="Tab 4"> <af:clientAttribute name="tabindex" value="4"/> <af:clientListener method="setTabIndex('1','4')" type="keyPress"/> </af:inputText> <af:inputText id="it6" label="Tab 2"> <af:clientAttribute name="tabindex" value="2"/> <af:clientListener method="setTabIndex('1','4')" type="keyPress"/> </af:inputText> </af:panelFormLayout> </af:panelHeader>To get the clientAttribute value in javscript you can use this in javascript , component.getProperty("tabindex") Or you can do a Javascript callback
function setTabIndex( min, max) { return function (evt) { var minTabIndex = min; var maxTabIndex = max; var keyCodePressed = evt.getKeyCode(); var keyModifiers = evt.getKeyModifiers(); var component = evt.getSource(); var panelForm = component.getParent(); if ( keyCodePressed == AdfKeyStroke.TAB_KEY ) { evt.cancel(); var tabIndex = parseInt(component.getProperty("tabindex")); } } }
Next question will be, how can you invoke a method in a managed bean (serverside) from the clientside. For this we can use af:serverListener, but you can not invoke this managed bean method directly. You need to fire a client ADF Event from the clientListener method. like this AdfCustomEvent.queue( source, "clickOnRow", {}, false);
<af:table value="#{bindings.allDepartments.collectionModel}" var="row" rows="#{bindings.allDepartments.rangeSize}" emptyText="#{bindings.allDepartments.viewable ? 'No data to display.' : 'Access Denied.'}" fetchSize="#{bindings.allDepartments.rangeSize}" rowBandingInterval="0" rowSelection="single" id="departmentTable" width="400" selectedRowKeys="#{bindings.allDepartments.collectionModel.selectedRow}"> <af:clientListener method="clickRow" type="click"/> <af:serverListener type="clickOnRow" method="#{Client.goCurrentRow}"/> <af:column sortProperty="departmentId" sortable="false" headerText="#{bindings.allDepartments.hints.departmentId.label}" id="c1"> <af:outputText value="#{row.departmentId}" id="ot3"> <af:clientAttribute name="departmentId" value="#{row.departmentId}"/> <af:clientListener method="showPopup('::deptPopup','dialog1','departmentId')" type="click"/> </af:outputText> </af:column> <af:column sortProperty="departmentName" sortable="false" headerText="#{bindings.allDepartments.hints.departmentName.label}" id="c2" width="200"> <af:outputText value="#{row.departmentName}" id="ot1"/> </af:column> </af:table>Here is the javascript for the ADF Client Event.
function clickRow(evt) { var source = evt.getSource(); AdfLogger.LOGGER.logMessage(AdfLogger.ERROR, "clickOnRow"); AdfCustomEvent.queue( source, "clickOnRow", {}, false); }And the managed bean method.
public void goCurrentRow(ClientEvent clientEvent) { // Determine which row is currently selected in the RichTable RichTable deptTable = (RichTable)clientEvent.getComponent(); Iterator keys = deptTable.getSelectedRowKeys().iterator(); while (keys.hasNext()) { Key key = (Key)((List)keys.next()).get(0); System.out.println(key.getKeyValues()[0]); } }
The only thing still to do is to debug the javascript methods. Start you Web application in FireFox and open the firebug application. Click on the script Tab.
Select the javascript file which you want to debug.
Set the breakpoint and debug through your application.
Here is my demo application with the following client examples ( thanks to Frank ).
- Hotkeys for Tab switching
- Tab Order
- Clear validation messages
- Type only numbers in a inputtext.
- Click on a record and invoke a managed bean method
- Click on a inputtext and display the value in a popup
Here you can download the demo workspace