Skip Headers
Oracle® Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework
11g Release 1 (11.1.1)

Part Number B31973-02
Go to Documentation Home
Home
Go to Book List
Book List
Go to Table of Contents
Contents
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
View PDF

5 Handling Events

This chapter describes how to handle events on the server as well as on the client.

This chapter includes the following sections:

5.1 Introduction to Events and Event Handling

In traditional JSF applications, event handling typically takes place on the server. JSF event handling is based on the JavaBeans event model, where event classes and event listener interfaces are used by the JSF application to handle events generated by components.

Examples of user events in an application include clicking a button or link, selecting an item from a menu or list, and changing a value in an input field. When a user activity occurs such as clicking a button, the component creates an event object that stores information about the event and identifies the component that generated the event. The event is also added to an event queue. At the appropriate time in the JSF lifecycle, JSF tells the component to broadcast the event to the appropriate registered listener, which invokes the listener method that processes the event. The listener method may trigger a change in the user interface, invoke backend application code, or both.

Like standard JSF components, ADF Faces command components deliver ActionEvent events when the components are activated, and ADF Faces input and select components deliver ValueChangeEvent events when the component local values change.

For example, in the File Explorer application, the File Menu contains a submenu whose commandMenuItem components allow a user to create a new file or folder. When users click the Folder commandMenuItem, an ActionEvent is invoked. Because the EL expression set as the value for the component's actionListener attribute resolves to the createNewDirectory method on the headerManager managed bean, that method is invoked and a new directory is created. Example 5-1 shows the code on the JSF page for the component, as well as the corresponding actionEvent listener method on the managed bean.

Example 5-1 JSF Page Code and Managed Bean Code for an ActionEvent Event

JSF code...
<af:commandMenuItem textAndAccessKey="#{explorerBundle['menuitem.folder']}"
                    shortDesc="#{explorerBundle['menuitem.folder']}"
                    accelerator="control T" useWindow="true"
                    windowHeight="300" windowWidth="600"
                    actionListener="#{explorer.headerManager.createNewDir}"/>

Managed bean code...
  public HeaderManager(FileExplorerBean feBean)
  {
    _feBean = feBean;
  }
...
  public void createNewDir(ActionEvent actionEvent)
  {
    // Create new FileItem of type DIRECTORY and 
    // ask FileExplorerBean to add it to current selected folder
    String newDirName = 
      _feBean.getFileExplorerBundle().getString("navigator.newfolder");
    FileItem newFileItem = new FileItem(newDirName);
    
    // set type to "Folder"
    FileItemProperty newFileItemProperty = newFileItem.getProperty();
    newFileItemProperty.setFileType(FileItemProperty.FileItemType.FOLDER);
 
    // Add new FileItem
    _feBean.getDataFactory().addNewFileItem(newFileItem, 
          NavigatorManager.removeRootFileName(_feBean.getSelectedDirectory()));
      
    // Refresh navigators, header, and content views through their managers
    _feBean.refreshAllManagers();
  }

Note:

Any ADF Faces component that has built-in event functionality must be enclosed in the form tag.

While ADF Faces adheres to standard JSF event handling techniques, it also enhances event handling in two key ways by providing:

5.1.1 Events and Partial Page Rendering

Unlike standard JSF events, ADF Faces events support AJAX-style partial postbacks to enable partial page rendering (PPR). Instead of full page rendering, ADF Faces events and components can trigger partial page rendering, that is, only portions of a page refresh upon request.

Certain events indicate a component is an event root component. Event root components determine boundaries on the page that allow the lifecycle to run just on components within that boundary (for more information about this aspect of the lifecycle, see Section 4.3, "Using the Optimized Lifecycle"), and only those components are refreshed on the page.

For example, the disclosure event sent when a expanding or collapsing a showDetail component (see Section 8.7, "Displaying and Hiding Contents Dynamically"), indicates that the showDetail component is a root. The lifecycle is run only on the showDetail component (and any children components or other components that point to this as a trigger), and only they are rerendered when it is expanded or collapsed.

Table 5-1 shows the event types in ADF Faces, and whether or not the source component is an event root.

Table 5-1 Events and Event Root Components

Event Type Component Trigger Is Event Root

action

All command components

false

dialog

dialog

false

disclosure

showDetail, showDetailHeader

true

disclosure

showDetailItem

true

focus

tree, treeTable

true

launch

All command components

NA

launchPopup

inputListOfValues, inputComboboxListOfValues

true

load

document

NA

poll

poll

true

popupOpened

popup

NA

popupOpening

popup

NA

popupClosed

popup

NA

propertyChange

All components

NA

queryEvent

query, quickQuery

true

queryOperation

query, quickQuery

true

rangeChange

table

NA

regionNavigation

region

NA

return

All command components

true

returnPopupData

inputListOfValues, inputComboboxListOfValues

true

returnPopup

inputListOfValues, inputComboboxListOfValues

true

rowDisclosure

tree, treeTable

true

selection

tree, treeTable, table

true

sort

treeTable, table

true

valueChange

All input and select components (components that implement EditableValueHolder)

true


5.1.2 Client-Side Event Model

In addition to server-side action and value change events, ADF Faces components also invoke client-side action and value change events, and other kinds of server and client events. Some events are generated by both server and client components (for example, selection events); some events are generated by server components only (for example, launch events); and some events are generated by client components only (for example, load events).

By default, most client events are propagated to the server. Changes to the component state are automatically synchronized back to the server to ensure consistency of state, and events are delivered, when necessary, to the server for further processing. However, you can configure your event so that it does not propagate.

In addition, any time you register a client-side event listener on the server-side Java component, the RCF assumes that you require a JavaScript component, so a client-side component is created.

Client-side JavaScript events can come from several sources: they can be derived automatically from DOM events, from property change events, or they can be manually created during the processing of other events.

5.2 Using ADF Faces Server Events

ADF Faces provides a number of server-side events. Table 5-2 lists the events generated by ADF Faces components on the server, and the components that trigger them.

Table 5-2 ADF Faces Server Events

Event Triggered by Component...

ActionEvent

All command components

DialogEvent

dialog

DisclosureEvent

showDetail, showDetailHeader, showDetailItem

FocusEvent **

tree, treeTable

LaunchEvent

All command components

LaunchPopupEvent

inputListOfValues, inputComboboxListOfValues

LoadEvent

document

PollEvent

poll

QueryEvent

query, quickQuery

QueryOperationEvent

query, quickQuery

RangeChangeEvent

table

RegionNavigationEvent

region

ReturnEvent

All command components

ReturnPopupEvent

inputListOfValues, inputComboboxListOfValues

RowDisclosureEvent

tree, treeTable

SelectionEvent

tree, treeTable, table

SortEvent

treeTable, table

ValueChangeEvent

All input and select components (components that implement EditableValueHolder)


** This focus event is generated when focusing in on a specific subtree, which is not the same as a client-side keyboard focus event.

All server events have associated event listeners. For example, to process a LaunchEvent event, you would create code that handles the event and then register it with the component as the listener.

5.2.1 How to Use Server-Side Events

To use server-side events, you create an event listener method in a backing bean and then register that method with the component.

To user server-side events:

  1. In a managed bean (or the backing bean for the page that will use the event listener), create a public method that accepts the event (as the event type) as the only parameter and returns void, as shown in Example 5-2. (For information about creating and using managed beans, see Section 2.6, "Creating and Using Managed Beans".)

    Example 5-2 Event Listener Method

    public void commandButton1_launchListener(LaunchEvent launchEvt)
    {
     
    // Event code here...
     
    }
    ...
    public void commandButton1_returnListener(ReturnEvent returnEvt)
    {
     
    // Event code here...
     
    }
    

    Tip:

    If the event listener code is likely to be used by more than one page in your application, consider creating an event listener implementation class that all pages can access. All server event listener implementations must override a processEvent() method, where Event is the event type.

    For example, the LaunchListener event listener accepts an instance of LaunchEvent as the single argument. In an implementation, you must override the event processing method, as shown in the following method signature:

    public void processLaunch (LaunchEvent evt) 
    {
      // your code here
    }
    
  2. To register an event listener method on a component, in the Structure window, select the component that will invoke the event. In the Property Inspector, use the dropdown menu next to the event listener property, and choose Edit.

  3. Use the Edit Property dialog to select the managed bean and method created in Step 1.

    Example 5-3 shows sample code for registering a launch event listener method and return event listener method on af:commandButton.

    Example 5-3 Registering an Event Listener Method

    <af:commandButton text="commandButton 1"
                      action="#{backing_pg1.commandButton1_action}"
                      launchListener="#{backing_pg1.commandButton1_launchListener}"
                      returnListener="#{backing_pg1.commandButton1_returnListener}"/>
    

5.3 Using JavaScript for ADF Faces Client Events

Most components can also work with client-side events. Handling events on the client saves a roundtrip to the server. When you use client-side events, instead of having managed beans contain the event handler code, you use JavaScript, which can be contained either on the calling page or in a JavaScript library.

By default, client events are processed only on the client. However, some event types are also delivered to the server, for example, AdfActionEvent events, which indicate a button has been clicked. Other events may be delivered to the server depending on the component state. For example, AdfValueChangeEvent events will be delivered to the server when the autoSubmit attribute is set to true. You can cancel an event from being delivered to the server if no additional processing is needed. However, some client events cannot be canceled. For example, because the popupOpened event type is delivered after the popup window has opened, this event delivery to the server cannot be canceled.

Performance Tip:

If no server processing is needed for an event, consider canceling the event at the end of processing so that the event does not propagate to the server. For more information, see Section 5.3.3, "How to Prevent Events from Propagating to the Server".

Table 5-3 lists the events generated by ADF Faces client components, whether or not events are sent to the sever, whether or not the events are cancelable, and the components that trigger the events.

Table 5-3 ADF Faces Client Events

Event Type Event Class Propagates to Server Can be Canceled Triggered by Component

action

AdfActionEvent

Yes

Yes

All command components

dialog

AdfDialogEvent

Yes

Yes

dialog

When user selects the OK or Cancel button in a dialog

disclosure

AdfDisclosureEvent

Yes

Yes

showDetail, showDetailHeader, showDetailItem

When the disclosure state is toggled by the user

 

AdfFocusEvent

Yes

Yes

tree, treeTable

 

AdfLaunchPopupEvent

Yes

Yes

inputListOfValues, inputComboboxListOfValues

load

AdfComponentEvent

Yes

Yes

document

When the document finished loading

 

AdfPollEvent

Yes

Yes

poll

popupOpened

AdfPopupOpenedEvent

No

No

popup

After a popup window or dialog is opened

popupOpening

AdfPopupOpeningEvent

No

Yes

popup

Prior to opening a popup window or dialog

popupClosed

AdfPopupClosedEvent

No

No

popup

After a popup window or dialog is closed

propertyChange

AdfPropertyChangeEvent

No

No

All components

query

AdfQueryEvent

Yes

Yes

query, quickQuery

Upon a query action (that is, when the user clicks the search icon or search button)

queryOperation

AdfQueryOperationEvent

Yes

Yes

query, quickQuery

 

AdfReturnEvent

Yes

Yes

All command components

 

AdfReturnPopupDataEvent

Yes

Yes

inputListOfValues, inputComboboxListOfValues

 

AdfReturnPopupEvent

Yes

Yes

inputListOfValues, inputComboboxListOfValues

rowDisclosure

AdfRowDisclosureEvent

Yes

Yes

tree, treeTable

When the row disclosure state is toggled

selection

AdfSelectionEvent

Yes

Yes

tree, treeTable, table

When the selection state changes

sort

AdfSortEvent

Yes

Yes

treeTable, table

When the user sorts the table data

valueChange

AdfValueChangeEvent

Yes

Yes

All input and select components (components that implement EditableValueHolder)

When the value of an input or select component is changed


The clientListener tag provides a declarative way to register a client-side event handler script on a component. The script will be invoked when a supported client event type is fired. Example 5-4 shows an example of a JavaScript function associated with an action event.

Example 5-4 clientListener Tag

<af:commandButton id="button0"
                  text="Do something in response to an action">
  <af:clientListener method="someJSMethod" type="action"/>
</af:commandButton>

Tip:

Use the clientListener tag instead of the component's JavaScript event properties.

The type attribute of the clientListener tag specifies the client event type that the tag will listen for, such as action or valueChange. The method attribute of the clientListener tag specifies the JavaScript function to call when the corresponding event is fired. The JavaScript function must take a single parameter, which is the event object.

The type attribute of the clientListener tag also supports client event types related to keyboard and mouse events. Table 5-4 lists the keyboard and mouse event types.

Table 5-4 Keyboard and Mouse Event Types Supported

Event Type Event Fires When...

click

User clicks a component

dblclick

User double-clicks a component

mousedown

User moves mouse down on a component

mouseup

User moves mouse up on a component

mousemove

User moves mouse while over a component

mouseover

Mouse enters a component

mouseout

Mouse leaves a component

keydown

User presses key down while focused on a component

keyup

User releases key while focused on a component

keypress

When a successful keypress occurs while focused on a component

focus

Component gains keyboard focus

blur

Component loses keyboard focus


Note:

Keyboard and mouse events wrap native DOM events using the AdfUIInputEvent subclass of the AdfBaseEvent class, which provides access to the original DOM event and also offers a range of convenience functions for retrieval of key codes, mouse coordinates, and so on. The AdfBaseEvent class also accounts for browser differences in how these events are implemented. Consequently, it is strongly recommended that developers avoid invoking the getNativeEvent() method on the directly, and instead use the AdfUIInputEvent API.

To use client-side events, you need to first create the JavaScript that will handle the event. For information about creating JavaScript, see Section 3.3, "Adding JavaScript to a Page". Within that functionality, you can add the following:

Once you create the JavaScript function, you must add an event listener that will call the event method. For more information, see Section 5.3.4, "How to Trigger Event Handler Execution".

5.3.1 How to Return the Original Source of the Event

The JavaScript method getSource() returns the original source of a client event. For example, the File Explorer application contains the showAboutFileExplorerPopup function shown in Example 5-5, that could be used by multiple events to set the alignment on a given popup dialog or window, using client attributes to pass in the values. Because each event that uses the function may have different values for the attributes, the function must know which source fired the event so that it can access the corresponding attribute values (for more about using client attributes, see Section 5.3.2, "Using Client-Side Attributes for an Event").

Example 5-5 Finding the Source Component of a Client Event

Explorer.showAboutFileExplorerPopup = function(event)
{
  var source = event.getSource();
  var alignType = source.getProperty("align");
  var alignCompId = source.getProperty("alignId"); 
  var popupCompId = source.getProperty("popupCompId");
  
  source.show({align:alignType, alignId:alignCompId});
  
  event.cancel();
}

The getSource() method is called to determine the client component that fired the current focus event, which in this case is the popup component.

5.3.2 Using Client-Side Attributes for an Event

There may be cases when you want the script logic to cause some sort of change on a component. To do this, you may need attribute values passed in by the event. For example, the File Explorer application contains the showAboutFileExplorerPopup function shown in Example 5-6, that can be used to set the alignment on a given popup component, using client attributes to pass in the values. The attribute values are accessed by calling the getProperty method on the source component.

Example 5-6 Attribute Values Are Accessed from JavaScript

Explorer.showAboutFileExplorerPopup = function(event)
{
  var source = event.getSource();
  var alignType = source.getProperty("align");
  var alignCompId = source.getProperty("alignId"); 
  var popupCompId = source.getProperty("popupCompId");
  
  var aboutPopup = event.getSource().findComponent(popupCompId);  
  aboutPopup.show({align:alignType, alignId:alignCompId});
  
  event.cancel();
}

The values are set on the source component, as shown in Example 5-7. For more information about setting components on the JSF page, see Section 5.3.4, "How to Trigger Event Handler Execution".

Example 5-7 Setting Attributes on a Component

<af:commandMenuItem id="aboutMenuItem"
                    text="#{explorerBundle['menuitem.about']}"
                    clientComponent="true">
  <af:clientListener method="Explorer.showAboutFileExplorerPopup"
                     type="action"/>
  <af:clientAttribute name="popupCompId" value=":aboutPopup"/>
  <af:clientAttribute name="align" value="end_after"/>
  <af:clientAttribute name="alignId" value="aboutMenuItem"/>
</af:commandMenuItem>

Using attributes in this way allows you to reuse the script across different components, as long as they all trigger the same event.

5.3.3 How to Prevent Events from Propagating to the Server

By default, some client events propagate to the server once processing has completed on the client. In some circumstances, it is desirable to block this propagation. For instance, if you are using a commandButton component to execute JavaScript code when the button is clicked, and there is no actionListener event listener on the server, propagation of the event is a waste of resources. To block propagation to the server, you call the cancel() function on the event in your listener. Once the cancel() function has been called, the isCanceled() function will return true.

Example 5-8 shows the showAboutFileExplorerPopup function, which cancels its propagation.

Example 5-8 Canceling a Client Event from Propagating to the Server

Explorer.showAboutFileExplorerPopup = function(event)
{
  var source = event.getSource();
  var alignType = source.getProperty("align");
  var alignCompId = source.getProperty("alignId"); 
  var popupCompId = source.getProperty("popupCompId");
  
  var aboutPopup = event.getSource().findComponent(popupCompId);  
  aboutPopup.show({align:alignType, alignId:alignCompId});
  
  event.cancel();
}

Canceling an event may also block some default processing. For example, canceling an AdfUIInputEvent event for a context menu will block the browser from showing a context menu in response to that event.

The cancel() function call will be ignored if the event cannot be canceled, which an event indicates by returning false from the isCancelable() function (events that cannot be canceled show "no" in the Is Cancelable column in Table 5-3). This generally means that the event is a notification that an outcome has already completed, and cannot be blocked. There is also no way to uncancel an event once it has been canceled.

5.3.4 How to Trigger Event Handler Execution

Once you have written the JavaScript methods, you use the clientListener tag on the JSF page to attach the appropriate JavaScript methods to the components whose events should trigger the method execution.

To use a client listener to trigger method execution:

  1. Select the component to invoke the JavaScript, and in the Property Inspector, set the ClientComponent attribute to true.

  2. Add a clientListener tag by dragging a Client Listener from the Operations panel of the Component Palette, and dropping it as a child to the selected component.

  3. In the Insert Client Listener dialog, enter the method and select the type for the JavaScript function. Be sure to include a library name if the script is not included on the page. See Table 5-3 and Table 5-4 for a list of the supported client event types.

    Example 5-9 shows the code used to invoke the showHelpFileExplorerPopup function from the Explorer.js JavaScript file.

    Example 5-9 clientListener Tags on JSF Page

    <af:commandMenuItem id="feedbackMenuItem"
                        text="#{explorerBundle['menuitem.feedback']}"
                        clientComponent="true">
      <af:clientListener method="Explorer.showHelpFileExplorerPopup"
                         type="action"/>
    </af:commandMenuItem>
    
  4. Add any attributes required by the function by dragging a Client Attribute from the Operations panel of the Component Palette, and dropping it as a child to the selected component. Enter the name and value for the attribute in the Property Inspector. Example 5-10 shows the code used to set attribute values for the showAboutFileExplorerPopup function.

    Example 5-10 Adding Attributes

    <af:commandMenuItem id="aboutMenuItem"
                         text="#{explorerBundle['menuitem.about']}"
                         clientComponent="true">
        <af:clientListener method="Explorer.showAboutFileExplorerPopup"
                            type="action"/>
        <af:clientAttribute name="popupCompId" value=":fe:aboutPopup"/>
        <af:clientAttribute name="align" value="end_after"/>
        <af:clientAttribute name="alignId" value="aboutMenuItem"/>
      </af:commandMenuItem>
    

    Note:

    If you use the attribute tag (instead of the clientAttribute tag) to add application-specific attributes or bonus attributes to a server component, those attributes are not included on the client component equivalent. You can use the clientAttribute tag on the JSF page, and the value will then be available on both the server and client. For information about posting client values back to the server, see Section 5.4, "Sending Custom Events from the Client to the Server". For information about bonus attributes, see Section 3.7, "Using Bonus Attributes for Client-Side Components".

5.3.5 What Happens at Runtime: How Client-Side Events Work

Event processing in general is taken from the browser's native event loop. The page receives all DOM events that bubble up to the document, and hands them to the peer associated with that piece of DOM. The peer is responsible for creating a rich client JavaScript event object that wraps that DOM event, returning it to the page, which queues the event (for more information about peers and the ADF Faces architecture, see Chapter 3, "Using ADF Faces Architecture".

The event queue on the page most commonly empties at the end of the browser's event loop once each DOM event has been processed by the page (typically, resulting in a component event being queued). However, because it is possible for events to be queued independently of any user input (for example, poll components firing their poll event when a timer is invoked), queueing an event also starts a timer that will force the event queue to empty even if no user input occurs.

The event queue is a First-In-First-Out queue. For the event queue to empty, the page takes each event object and delivers it to a broadcast() function on the event source. This loop continues until the queue is empty. It is completely legitimate (and common) for broadcasting an event to indirectly lead to queueing a new, derived event. That derived event will be broadcast in the same loop.

When an event is broadcast to a component, the component does the following:

  1. Delivers the event to the peer's DispatchComponentEvent method.

  2. Delivers the event to any listeners registered for that event type.

  3. Checks if the event should be bubbled, and if so initiates bubbling. Most events do bubble. Exceptions include property change events (which are not queued, and do not participate in this process at all) and, for efficiency, mouse move events.

    While an event is bubbling, it is delivered to the AdfUIComponent HandleBubbledEvent function, which offers up the event to the peer's DispatchComponentEvent function. Note that client event listeners do not receive the event, only the peers do.

    Event bubbling can be blocked by calling an event's stopBubbling() function, after which the isBubblingStopped() function will return true, and bubbling will not continue. As with cancelling, you cannot undo this call.

    Note:

    Canceling an event does not stop bubbling. If you want to both cancel an event and stop it from bubbling, you must call both functions.
  4. If none of the prior work has canceled the event, calls the AdfUIComponent.HandleEvent method, which adds the event to the server event queue, if the event requests it.

5.3.6 What You May Need to Know About Using Naming Containers

Several components in ADF Faces are NamingContainer components, such as pageTemplate, subform, table, and tree. When working with client-side API and events in pages that contain NamingContainer components, you should use the findComponent() method on the source component.

For example, because all components in any page within the File Explorer application eventually reside inside a pageTemplate component, any JavaScript function must use the getSource() and findComponent() methods, as shown in Example 5-11. The getSource() method accesses the AdfUIComponent class, which can then be used to find the component.

Example 5-11 JavaScript Using the findComponent() Method

function showPopup(event)
{
  event.cancel();
  var source = event.getSource();
  var popup = source.findComponent("popup");
  popup.show({align:"after_end", alignId:"button"});
}

When you use the findComponent() method, the search starts locally at the component where the method is invoked. For more information about working with naming containers, see Section 3.5, "Locating a Client Component on a Page".

5.4 Sending Custom Events from the Client to the Server

While the clientAttribute tag supports sending bonus attributes from the server to the client, those attributes are not synchronized back to the server. To send any custom data back to the server, use a custom event sent through the AdfCustomEvent class and the serverListener tag.

The AdfCustomEvent.queue() JavaScript method enables you to fire a custom event from any component whose clientComponent attribute is set to true. The custom event object contains information about the client event source and a map of parameters to include on the event. The custom event can be set for immediate delivery (that is, during the Apply Request Values phase), or non-immediate delivery (that is, during the Invoke Application phase).

For example, in the File Explorer application, after entering a file name in the search field on the left, users can press the Enter key to invoke the search. As Example 5-12 shows, this happens because the inputText field contains a clientListener that invokes a JavaScript function when the Enter key is pressed.

Example 5-12 clientListener Invokes JavaScript Function and Causes ServerLIstener to Be Invoked

//Code on the JSF page...
<af:inputText id="searchCriteriaName"
              value="#{explorer.navigatorManager.searchNavigator.
                                               searchCriteriaName}"
              shortDesc="#{explorerBundle['navigator.filenamesearch']}">
  <af:serverListener type="enterPressedOnSearch"
                     method="#{explorer.navigatorManager.
                                        searchNavigator.searchOnEnter}"/>
  <af:clientListener type="keyPress"
                     method="Explorer.searchNameHandleKeyPress"/>
</af:inputText>

//Code in JavaScript file...
Explorer.searchNameHandleKeyPress = function (event)
{
  if (event.getKeyCode()==AdfKeyStroke.ENTER_KEY)
  {
    var source = event.getSource();
    AdfCustomEvent.queue(source,
                         "enterPressedOnSearch", 
                         {}, 
                         false);
  } 
}

The JavaScript contains the AdfCustomEvent.queue method that takes the event source, the string enterPressedOnSearch as the custom event type, a null parameter map, and False for the immediate parameter.

The inputText component on the page also contains the following serverListener tag:

<af:serverListener type="enterPressedOnSearch"
                   method="#{explorer.navigatorManager.
                                      searchNavigator.searchOnEnter}"/>

Because the type value enterPressedOnSearch is the same as the value of the parameter in the AdfCustomEvent.queue method in the JavaScript, the method that resolves to the method expression #{explorer.navigatorManager.searchNavigator.searchOnEnter} will be invoked.

5.4.1 How to Send Custom Events from the Client to the Server

To send a custom event from the client to the server, you need to fire the client event using a custom event type, write the server listener method on a backing bean, and have this method process the custom event. You then need to register the server listener with the component.

To send custom events:

  1. Create the JavaScript that will handle the custom event using the AdfCustomEvent.queue() method to provide the event source, custom event type, and the parameters to send to the server.

    For example, the JavaScript used to cause the pressing of the Enter key to invoke the search functionality uses the AdfCustomEvent.queue method that takes the event source, the string enterPressedOnSearch as the custom event type, a null parameter map, and False for the immediate parameter, as shown in Example 5-13.

    Example 5-13 Sample JavaScript for Custom Events

    Explorer.searchNameHandleKeyPress = function (event)
    {
      if (event.getKeyCode()==AdfKeyStroke.ENTER_KEY)
      {
        var source = event.getSource();
        AdfCustomEvent.queue(source,
                             "enterPressedOnSearch", 
                             {}, 
                             false);
      } 
    }
    
  2. Create the server listener method on a managed bean. This method must be public and take an oracle.adf.view.rich.render.ClientEvent object and return a void type. Example 5-14 shows the code used in the SearchNavigatorView managed bean that simply calls another method to execute the search and then refreshes the navigator.

    Example 5-14 Server Listener Method for a Custom Client Event

    public void searchOnEnter(ClientEvent clientEvent)
      {
        doRealSearchForFileItem();
        
        // refresh search navigator
        this.refresh();
      }
    

    Note:

    The Java-to-JavaScript transformation can lose type information for Numbers, chars, Java Objects, arrays, and nonstring CharSequences. Therefore, if an object being sent to the server was initially on the server, you may want to add logic to ensure the correct conversion. See Section 5.4.3, "What You May Need to Know About Marshalling and Unmarshalling of Data".
  3. Register the clientListener by dragging a Client Listener from the Operations panel of the Component Palette, and dropping it as a child to the component that raises the event.

    Note:

    On the component that will fire the custom client event, the clientComponent attribute must be set to true to ensure that a client-side generated component is available.
  4. In the Insert Client Listener dialog, enter the method and type for the JavaScript function. Be sure to include a library name if the script is not included on the page. The type can be any string used to identify the custom event, for example, enterPressedOnSearch was used in the File Explorer.

  5. Register the server listener by dragging a Server Listener from the Operations panel of the Component Palette, and dropping it as a sibling to the clientListener tag.

  6. In the Insert Server Listener dialog, enter the string used as the Type value for the client listener, as the value for this server listener, for example enterPressedOnSearch.

    In the Property Inspector, for the method attribute, enter an expression that resolves to the method created in Step 2.

5.4.2 What Happens at Runtime: How Client and Server Listeners Work Together

At runtime, when the user initiates the event, for example, pressing the Enter key, the client listener script executes. This script calls the AdfCustomEvent.queue() method, and a custom event of the specified event type is queued on the input component. The server listener registered on the input component receives the custom event, and the associated bean method executes.

5.4.3 What You May Need to Know About Marshalling and Unmarshalling of Data

Marshalling and unmarshalling is the process of converting data objects of a programming language into a byte stream and back into data objects that are native to the same or a different programming language. In ADF Faces, marshalling and unmarshalling refer to transformation of data into a suitable format so that it can be optimally exchanged between JavaScript on the client end and Java on the server end. When the client is browser-based, the two common strategies for marshalling are JavaScript Object Notation (JSON) and XML. ADF Faces uses a mix of both of these strategies, with the information sent from the server to the client mostly as JSON and information sent from the client to the server as XML (for more information about JSON, see http://www.json.org).

When you send information from JavaScript to Java, the JavaScript data objects are converted (marshalled) into XML, which is then parsed back or unmarshalled into Java objects at the server-side. For example, consider a JSF page that has a commandButton component whose ID is cmd. When a user clicks the commandButton component, the client must communicate to the server that an actionEvent has been fired by this specific commandButton. In the requestParameter map, the information is mapped with the key using the format event + . + id where id is the ID of the component. So the requestParameter map key for the commandComponent would be the XML string stored as the value of the key event.cmd.

The XML fragment after marshalling in this example would be:

<m xmlns="http:/oracle.com/richClient/comm"><k v="type"><s>action</s></k></m>

The m in the example means that this should be unmarshalled into a map. The k denotes the key and the value is of type String. On the server side, this XML fragment is parsed into a java.util.Map of one entry having type (java.lang.String) as the key and action (java.lang.String) as the value.

The unmarshalled information is grouped per client ID, stored in the request map, and used when the components are being decoded. So in this example, when the commandButton is decoded, it will check for the presence of any client events using its client ID (event.cmd) and then queue an action event if one is found (the decode behavior is implemented in the renderer hierarchy for commandButton component).

Table 5-5 shows the mapping between corresponding JavaScript and Java types.

Table 5-5 JavaScript to Java Type Map

JavaScript Type Java Type

Boolean

java.lang.Boolean

Number

java.lang.Double

String

java.lang.String

Date

java.util.Date

Array

java.util.ArrayList

Object

java.util.Map


Marshalling from Java to JavaScript happens mostly through JSON. This type of marshalling is straightforward as JSON is the object literal notation in JavaScript. The client-components usually have their properties encoded in JSON. Consider the following example:

new AdfRichCommandButton('demoTemplate:richComand'
    {'partialSubmit':true,'useWindow':false})

The second argument ({'partialSubmit':true,'useWindow':false}) is a JSON object. There is no additional unmarshalling step required at the browser end as JSON can directly be parsed into the JavaScript environment as an object.

Encoding for a table also uses JSON to pass push messages to the client. The following is an example of an envelope containing a single encoded push message:

[{'rKey':'0','type':'update','data':[{'val':'Active Data Every Second: on row 0:78','prop':'value','cInd':0},{'val':'Active Data Every Second: on row 0:78','prop':'value','cInd':1}]}]

The envelope is a JavaScript Array with only one object, which describes the message. This message contains information about the type of change, the actual value of the data, and so on, that is then used by the client-side table peer to update the table itself.

Table 5-6 shows the mapping between corresponding Java and JavaScript types.

Table 5-6 Java to JavaScript Type Map

Java Type JavaScript Type

java.lang.Boolean

Boolean

java.lang.Double

Number

java.lang.Integer

Number

java.lang.Float

Number

java.lang.Long

Number

java.lang.Short

Number

java.lang.Character

String

java.lang.CharSequence

String

java.util.Collection

Array

java.util.Date

Date

java.util.Map

Object

Array

Array

java.awt.Color

TrColor


Note that there could be some loss of information during the conversion process. For example, say you are using the following custom event to send the number 1 and the String test, as shown in the following example:

AdfCustomEvent.queue(event.getSource(), "something", {first:1, second:"test"});

In the server-side listener, the type of the first parameter would become a java.lang.Double because numbers are converted to Doubles when going from JavaScript to Java. However, it might be that the parameter started on the server side as an int, and was converted to a number when conversion from Java to JavaScript took place. Now on its return trip to the server, it will be converted to a Double.

5.5 Executing a Script Within an Event Response

Using the ExtendedRenderKitService class, you can add JavaScript to an event response, for example, after invoking an action method binding. It can be a simple message like sending an alert informing the user that the database connection could not be established, or a call to a function like hide() on a popup window to programatically dismiss a popup dialog.

For example, in the File Explorer application, when the user clicks the UpOneFolder navigation button to move up in the folder structure, the folder pane is repainted to show the parent folder selected. The HandleUpOneFolder() method is called in response to clicking the UpOneFolder button event. It uses the ExtendedRenderKitService class to add JavaScript to the response.

Example 5-15 shows the UpOneFolder code in the page with the actionListener attribute bound to the HandleUpOneFolder() handler method which will process the action event when the button is clicked.

Example 5-15 Invoking a Method to Add JavaScript to a Response

<af:commandToolbarButton id="upOneFolder"
        icon="/fileExplorer/images/uponefolder_ena.png"
        depressedIcon="/fileExplorer/images/uponefolder_dwn.png"
        disabledIcon="/fileExplorer/images/uponefolder_dis.png"
        hoverIcon="/fileExplorer/images/uponefolder_ovr.png"
        shortDesc="#{explorerBundle['toolbarbutton.uptooltip']}"
        disabled="#{explorer.headerManager.disabledUpOneFolder}"
        actionListener="#{explorer.headerManager.handleUpOneFolder}"/>

Example 5-16 shows the handleUpOneFolder method that uses the ExtendedRenderKitService class.

Example 5-16 Adding JavaScript to a Response

public void handleUpOneFolder(ActionEvent actionEvent)
 {
   UIXTree folderTree = 
     feBean.getNavigatorManager().getFoldersNavigator().getFoldersTreeComponent();
   Object selectedPath = 
    feBean.getNavigatorManager().getFoldersNavigator().getFirstSelectedTreePath();
    
   if (selectedPath != null)
    {
      TreeModel model = 
        _feBean.getNavigatorManager().getFoldersNavigator().getFoldersTreeModel();
      Object oldRowKey = model.getRowKey();
      try
      {
        model.setRowKey(selectedPath);
        Object parentRowKey = model.getContainerRowKey();
        if (parentRowKey != null)
        {
          folderTree.getSelectedRowKeys().clear();
          folderTree.getSelectedRowKeys().add(parentRowKey);
          // This is an example of how to force a single attribute
          // to rerender. The method assumes that the client has an optimized
          // setter for "selectedRowKeys" of tree.
          FacesContext context =  FacesContext.getCurrentInstance();
          ExtendedRenderKitService erks =
            Service.getRenderKitService(context,
                    ExtendedRenderKitService.class);
          String clientRowKey = folderTree.getClientRowKeyManager().
            getClientRowKey(context, folderTree, parentRowKey);
          String clientId = folderTree.getClientId(context);
          StringBuilder builder = new StringBuilder();
          builder.append("AdfPage.PAGE.findComponent('");
          builder.append(clientId);
          builder.append("').setSelectedRowKeys({'");
          builder.append(clientRowKey);
          builder.append("':true});");
          erks.addScript(context, builder.toString());
        }
      }
      finally
      {
        model.setRowKey(oldRowKey);
      }
      // Only really needed if using server-side rerendering
      // of the tree selection, but performing it here saves
      // a roundtrip (just one, to fetch the table data, instead
      // of one to process the selection event only after which
      // the table data gets fetched!)
      _feBean.getNavigatorManager().getFoldersNavigator().openSelectedFolder();
    } 
    
  }

5.6 Using Client Behavior Tags

ADF Faces client behavior tags provide declarative solutions to common client operations that you would otherwise have to write yourself using JavaScript, and register on components as client listeners. By using these tags instead of writing your own JavaScript code to implement the same operations, you reduce the amount of JavaScript code that needs to be downloaded to the browser.

ADF Faces supports two client behaviors you can use in place of client listeners: showPopupBehavior and showPrintablePageBehavior. The showPopupBehavior tag enables you to display contents in a popup (through the popup component), in response to a user activity such as clicking a button. The showPrintablePageBehavior tag enables you to generate and display a printable version of the current page when users activate a command component. Both components do not work on their own, but must be associated with other components.

Typically, you would associate a showPopupBehavior tag with a command component, such as a commandButton component, to provide a button for users to activate and display contents in a popup. For details on how to use af:showPopupBehavior, see Chapter 13, "Using Popup Dialogs, Menus, and Windows".

Note:

The showPopupBehavior tag cancels server-side event delivery automatically. Therefore, any actionListener or action attributes on the parent component will be ignored. This cannot be disabled. Developers that need to also trigger server-side functionality should either use a client-side event to show a popup (see Section 5.3, "Using JavaScript for ADF Faces Client Events"), or add an additional client listener that uses AdfCustomEvent and af:serverListener to deliver a server-side event (see Section 5.4, "Sending Custom Events from the Client to the Server").

You use af:showPrintablePageBehavior with a component whose contents you want users to be able to print when a command component is activated. When the command component is activated, a request is sent to the server to get a printable page; the action event, which is typically fired when a command component is activated, is not sent. ADF Faces displays the printable version of the page in a new browser window or in a new tab in the browser window. The printable page does not render scrollbars or any navigation items such as buttons, tabs, or menus. For details on how to use the showPrintablePageBehavior tag with the panelStretchLayout, panelSplitter, panelBorderLayout, or showDetailItem component, see the corresponding section in Chapter 8, "Organizing Content on Web Pages".