by Martin Giffy D’Souza
Dynamic actions were first introduced in APEX 4.0. They allow developers to declaratively define actions based on browser events. This chapter will cover all aspects of dynamic actions including creating and modifying dynamic actions and how dynamic actions can interact with each other. This chapter is divided into three main sections. It will first compare the manual way of manipulating browser events using custom JavaScript to create a dynamic action. The second section will cover all the options and features available with dynamic actions. The last section will present a detailed example of using multiple dynamic actions.
This chapter assumes you are familiar with APEX and have a basic understanding of the following web technologies:
If you are unfamiliar with any of these languages or need additional information, please go to www.w3schools.com. The JavaScript examples provided in this chapter will use jQuery, which is included as part of APEX 5.
Note APEX 5 supports two development methods: Component View and Page Designer. Component view is the old (APEX 4 and older) developer page with the traditional Page Rendering, Page Processing, and Shared Components columns. The new Page Designer is a more modern IDE. It has a three-column development page that does not require wizards for each step. For the purpose of this chapter, all examples will use the new Page Designer view and refer to the three columns as the left, central, and right panes.
Custom JavaScript vs. Dynamic Actions
The best way to highlight dynamic actions is to compare them to the manual method using custom JavaScript. This section will examine a simple problem you may have faced when developing an APEX application and show how to resolve it first manually and then using a dynamic action. The purpose is to demonstrate the manual versus dynamic action way to handle browser-based events in APEX.
Suppose you have a select list for a department (P1_DEPTNO) and employees (P1_EMPNO) on page 1. If no department is selected, the list of employees should not be displayed, as shown in Figure 8-1. Once a department is selected, the list of employees should appear, as shown in Figure 8-2. The two subsections that follow compare the different ways to implement the functionality shown in the figures.
Figure 8-1. No department selected
Figure 8-2. Department selected
Manual (Custom JavaScript) Method
Prior to APEX 4, if you wanted to perform an action based on a browser event, you needed to write custom JavaScript code. Writing custom JavaScript code poses several issues.
The following JavaScript example shows how to toggle a field based on a browser event prior to APEX 4. This code snippet needs to be included in your page. Since there are multiple ways to include it in your page, it can be hard for someone to track down where the code is stored.
/**
* Toggle Empno based on P1_DEPTNO’s value
*/
function showHideEmpno(){
if ($v(’P1_DEPTNO’) == ’’)
$x_HideItemRow(’P1_EMPNO’);
else
$x_ShowItemRow(’P1_EMPNO’);
}//showHideEmpno
//Wait for page to be ready
$(document).ready(function() {
//Show/Hide Empno after page load
showHideEmpno();
//Register browser event (onChange)
$(’#P1_DEPTNO’).on(’change’,function(){showHideEmpno();});
});
Dynamic Action Method
Starting in APEX 4, you can declaratively trigger actions based on browser events using dynamic actions. Dynamic actions are a preferred method over custom JavaScript functions because of the following reasons:
The following steps describe how to toggle the Employee field, as was done in the previous example, using a dynamic action. This example does not cover each step in detail since the goal is to quickly compare the manual method with the dynamic action. The next section of this chapter will describe each of the available options in detail.
Figure 8-3. Click the Dynamic Actions icon
Figure 8-4. Create Dynamic Action menu item
Figure 8-5. Newly created dynamic action
Figure 8-6. Page Designer Messages notifications
Figure 8-7. Dynamic Action properties
Figure 8-8. True Action properties
Figure 8-9. Create Opposite Action menu item
Dynamic actions have a lot of benefits; however, there are some situations where you may want use custom JavaScript, primarily for performance and control issues. For example, if you have a client-side action that needs to be performed as quickly as possible, then manually coding it using JavaScript may be a better approach. Dynamic actions add a minimal amount of overhead compared to certain manual techniques. In most situations, this additional overhead is not significant nor will it degrade the performance of your application.
Dynamic Actions in Detail
This section will cover all the options available for dynamic actions and will reference the OnChange DeptNo dynamic action that was created in the previous section.
An easy way to understand dynamic actions is to break down their components into two main parts: drivers and actions. The driver determines what causes a dynamic action to run and when an action is triggered. Actions contain the code to perform the tasks. In the previous example, the driver is when the P1_DEPTNO select list is changed. The actions is to either show or hide the P1_EMPNO select list. Figure 8-10 highlights the driver and actions concept as part of a flow chart. In Figure 8-10, DA stands for dynamic action.
Figure 8-10. Dynamic action flow chart
When modifying a dynamic action, the When and Advanced sections allow you to define the driver. The True and False actions define the actions to perform based on a real-time condition.
To edit a dynamic action, simply click the Dynamic Actions icon (shown earlier in Figure 8-3) and click the desired dynamic action. Alternatively, you can select the rendering icon in the left pane, as shown in Figure 8-11. Then expand the P1_DEPTNO item and click its dynamic actions, as shown in Figure 8-12.
Figure 8-11. Rendering icon
Figure 8-12. Dynamic action under page item
Note When a dynamic action is linked to a region or an item, it will also appear in the region’s or item’s tree entry in the left pane.
Editing a dynamic action will display its properties in the right pane. The following sections will cover each of these options, except for the standard sections (Condition, Authorization, Configuration, Comments) that are found in most APEX objects. If a section does not appear in your current view, try to toggle between the property editor’s view options, Show Command and Show All, as shown in Figure 8-13.
Figure 8-13. Property editor view options
Identification
The Identification section, as shown in Figure 8-14, is similar to other objects in APEX. You can define a name and a sequence. Although the name will not be displayed to the end user, a meaningful name is useful for other developers modifying your application.
Figure 8-14. Dynamic action: Identification
Dynamic actions can have multiple actions, so it is recommended that you come up with a naming scheme that works for your organization. One naming scheme that has proven useful is to name the dynamic action based on the triggering event.
Execution Options
The Execution Options section, as shown in Figure 8-15, sets the sequence number. The sequence number determines the order in which dynamic actions are performed. If an action is set to fire on page load, the sequence number will determine the order of the actions, regardless of their triggering event, during the page load. After the page is loaded, the sequence is relevant only if you have multiple dynamic actions that are executed by the same event.
Figure 8-15. Dynamic action: Execution Options
When
APEX dynamic actions bind events to objects that you specify in the When section. When the defined event occurs on the objects, APEX will run the appropriate actions. Figure 8-16 shows the When section for the onChange Deptno dynamic action.
Figure 8-16. Dynamic action: When
There are three main components to the When section: Event, Selection Type, and Condition. If you click each of these labels, you’ll get some excellent documentation about each of these components. You can find the documentation in the Help tab in the central pane, as shown in Figure 8-17.
Figure 8-17. Help tab
Event
Dynamic actions are triggered by browser-based events. These events are invoked by a user’s actions or by JavaScript. The event determines which event will trigger the dynamic action to run. In the example, the dynamic action is set to run when the user changed the value for P1_DEPTNO, so the Change event was selected.
Events are grouped into four main categories: Browser, Framework, Component, and Custom events. Browser events are standard HTML events (for more information about HTML event types, please refer to the jQuery event documentation: http://api.jquery.com/category/events). Framework events are triggered by APEX-specific events. For example, the After Refresh event is triggered after a report region is refreshed as part of report pagination. Component events are triggered by specific objects within APEX or by plug-ins. Custom events allow you to define a JavaScript event name to listen to. Use this option only if the required event is not available in the list of drop-down events. The following site covers custom events in detail: https://learn.jquery.com/events/introduction-to-custom-events.
Selection Type
The event option will determine which events APEX needs to “listen” for. The Selection Type option and its corresponding object determine the objects to listen on. In the example, Item(s) was selected. This means that APEX will wait for a change to occur on P1_DEPTNO. Once a user changes the P1_DEPTNO select list, the onChange DeptNo dynamic action will be triggered. There are five different selection types to choose from: Item(s), Button, Region, jQuery Selector, and JavaScript Expression.
If the selection type is set to Item(s), you need to specify a comma-delimited list of items in the Item(s) field. APEX will listen to all the specified items and apply the same actions, regardless of which item was selected. When the dynamic action is triggered, APEX passes the specific item that triggered it as part of a JavaScript object (more on this later).
Similar to Item(s), when specifying a selection type of Button, you need to select a button from the current page. This allows you to easily control what happens when a user clicks a button in the page without submitting the page.
The Region selection allows you to select a single region for APEX to listen on. A good example of this is if you wanted to display a custom wait message each time an interactive report is refreshed. In this case, you’d set the event to Before Refresh, set the selection type to Region, and select the region that contains your interactive report.
When using a region as the selection type, it is important to ensure that the region’s template contains an ID. If the region’s template is set to No Template, APEX will not be able to register its listener on the region since the region does not contain an ID. For more information, read the following blog post: www.talkapex.com/2011/01/missing-id-in-no-template-region.html. If using the new APEX 5 universal theme, this should not be an issue.
Instead of listening on APEX-specific objects such as items or a region, you can specify a jQuery selector or a JavaScript expression. In most cases, the jQuery selector should be sufficient; however, they are cases when you want to use JavaScript expressions for more complex selections.
For example, if you wanted APEX to perform a dynamic action each time someone moved their mouse over an HTML element with a class of highlight-me, you would select jQuery Selector and enter .highlight-me, as shown in Figure 8-18. The jQuery Selector option uses jQuery notation. You can find detailed information about the jQuery selector notation on the jQuery API site: http://api.jquery.com/category/selectors.
Figure 8-18. When selection type: jQuery Selector
If JavaScript Expression is selected, it expects a DOM object, an array of DOM objects, or a jQuery object. Examples of a DOM object are objects such as document and window. The jQuery object can be any jQuery object such as a tree traversal. An example of this is using $(’p’).children() to select all the children of paragraph (p) elements. You can find more information about jQuery tree traversals here: http://api.jquery.com/category/traversing/tree-traversal/.
Condition
Dynamic actions allow you to perform different actions based on a condition. This condition is not the same as a standard APEX object condition. It is evaluated in real time against the triggering element each time the event occurs. If the condition is true or not defined, then the True actions are executed. If the condition is false, the False actions are performed.
In the example, the condition (previously shown in Figure 8-16) is set to “is not null.” This means that each time the triggering element P1_DEPTNO is changed, APEX will evaluate it to see whether it is null. If it is null, then it will hide the list of employees (False action). If a department is selected, it will show the list of employees (True action).
Figure 8-19 shows a list of conditions. All conditions, except for “is not null” and “is null,” require that you enter some additional information in the Value(s) field.
Figure 8-19. List of conditions
The value required for the first six comparison conditions is a static value. You can reference an item value, but you must use the substitution string &PX_ITEM_NAME. notation. If you use a substitution string, it will use the value of the item when the page is loaded, which may not be the same value that is currently on the page when the condition is evaluated.
The two list conditions compare static comma-delimited lists. If referencing a substitution string, the value of the item at the time the page is loaded will be used.
The last condition, “JavaScript expression,” allows you to compare values in real time when the condition is evaluated. All the other conditions are evaluated against the triggering element. If you use a JavaScript expression, you can compare any set of values. In most cases, part of the expression will include the triggering element.
The JavaScript expression condition type contains several objects.
If you want to quickly see all the additional information that is available in each of the attributes listed previously, set the condition to “JavaScript expression” and in the Value field enter console.log(this);, as shown in Figure 8-20. Refresh the page and trigger the event. If you look at the console, you will see the output of the this object, as shown in Figure 8-21.
Figure 8-20. Configuring condition to display this object
Figure 8-21. Console output of condition of this object
Note The console is available in most browsers (except for Internet Explorer 8 and older). The following list describes how to view the console output in each of the major browsers:
To demonstrate a condition that uses a JavaScript expression, add an additional Number Field item on page 1 called P1_X. Change the condition in the OnChange DeptNo dynamic action from “is not null” to JavaScript Expression. In the JavaScript Expression text area, enter this.triggeringElement.value > apex.item(’P1_X’).getValue(), as shown in Figure 8-22. Refresh the page and enter 20 in the P1_X field. When you change the department, the list of employees will appear only when you select Operations (40) and Sales (30). You’ll notice that if you change the value of P1_X, the condition will evaluate without having to submit the page or set the value in session state.
Figure 8-22. JavaScript condition
Advanced
The When section defines the events and objects that APEX should listen to. The Advanced section defines how the events are bound to the objects. There are three different ways to attach an event to an object, as shown in Figure 8-23.
Figure 8-23. Event scopes
For more information about attaching events, please refer to the following documentation: http://api.jquery.com/category/events/event-handler-attachment. The jQuery API contains additional event handler attachment options that are currently not available in APEX.
Actions
Prior to APEX 5, the True and False actions used were modifiable on the Dynamic Action edit page. Starting with APEX 5, they are now visible in the left pane under each dynamic action, as shown in Figure 8-24. They contain actions to perform based on the dynamic action’s condition. If multiple actions exist in each section, they will be synchronously executed in order (unless specified), determined by their sequence number.
Figure 8-24. True and False actions
Earlier in this chapter, you created the OnChange DeptNo dynamic action. The True/False Actions steps allowed you to define True and False actions (see Figure 8-8).
To help describe the options available when editing an action on the right pane, edit the True (Show) action by clicking it in the left pane, as shown in Figure 8-25. The action’s properties are now available in the right pane, as shown in Figure 8-26. The following subsections will describe all the options available when modifying an action.
Figure 8-25. Edit Show action
Figure 8-26. Edit action
Identification
The Identification section allows you to select the action that the action will perform. The options in the Action select list are broken up into six categories, as shown in Figure 8-27. The categories have no impact on the system and are there to help organize the list of available actions. This list also includes plugin dynamic actions that are suffixed with [Plug-in]. When the Action option selected, click the Help tab in the central pane to get a brief description for each of the built-in actions. Some actions require additional configuration, which is covered in the “Settings” and “Affected Elements” sections.
Figure 8-27. Action select list
Settings
The Settings section is available only for certain actions. Each Settings section is different depending on the action selected. In the example, the only available option is to show all page items on the same line. This section will cover the settings options for two different action types: Execute JavaScript Code and Execute PL/SQL Code.
Execute JavaScript Code: When the action is set to Execute JavaScript Code, the Settings section contains a text box where you can enter some JavaScript code to run. To help, APEX provides the this object that contains five different elements. this.triggeringElement, this.browserEvent, and this.data were already covered in the “Dynamic Actions Condition” section.
You can get an overview of these objects by clicking the Code label and clicking the Help tab in the central pane. To explore all the options available, enter console.log(this); in the Code section, refresh your page, trigger the dynamic action, and then look at the console window.
Execute PL/SQL Code: When the action is set to Execute PL/SQL Code, APEX will send an AJAX request to the database to execute the block of PL/SQL code. You can reference page and application items using bind variables in this block of code. It’s important to remember that the page and application items are the values in session state, which may not be the same as the values currently displayed on the page.
To submit page items as part of the AJAX request, enter them as a comma-delimited list in the Page Items to Submit field. If any of the items submitted as part of the action have session state protection enabled, the action will fail since the item requires a checksum, which is not provided in AJAX requests. This is done for security reasons to prevent malicious users from tampering with data.
Values from session state (page and application items) can be returned by the PL/SQL code by entering the item names in the Page Items to Return field. When doing so, the item’s value on the page will automatically be updated with the value in session state at the end of the action.
Affected Elements
The Affected Elements section allows you to define which elements on the page are impacted by the dynamic action. This section will show up only for actions that can affect an object on the page. In the example, the affected element type was Item(s) on P1_EMPNO since it needed to be shown and hidden. The different types of affected elements are as follows:
Not all actions require or allow for affected elements to be defined. For example, it doesn’t make sense for the Alert action type, which triggers a pop-up notification, to have any affected elements.
Execution Options
The Execution Options section (as shown in Figure 8-28) determines when to run the action based on the dynamic action’s condition. An action can be run when the condition is either true or false. Setting the value to True or False will determine which section the action is listed in, as shown in Figure 8-25.
Figure 8-28. Execution Options
You can choose whether to fire the action once the page is loaded. For the option to be run on page load, this option needs to be selected, and the dynamic action’s condition result must match the True/False setting during the page load. For example, both of the actions in the OnChange DeptNo dynamic action are set to fire on page load. Only one of these will actually be run during the page load based on the value of P1_DEPTNO at the time the dynamic action is executed. Some actions, such as Execute PL/SQL Code and Set Value, allow you to select additional attributes: Stop Execution On Error and Wait for Result, as shown in Figure 8-29.
Figure 8-29. Execution Options additional attributes
Dynamic Actions in Action
The example that was used in the previous sections was a basic Show/Hide dynamic action. This section will cover how to create more complex dynamic actions. All the available actions won’t be covered in this chapter; however, this example will make you familiar with some of them and how they can interact with one another. A final copy of this example is included in the book’s files as an application. The file is 08_example-2_finished_application.sql.
Note The following example will leverage some features available only in recent web browsers. If you are using Internet Explorer, please ensure that it is version 8 or newer.
Business Case
After showing users the previous example, they requested some modifications to the department/employee behavior. Instead of selecting an employee from a select list, they would like to select an employee from a report. The full list of requirements is as follows:
Using dynamic actions, you’ll be able to implement all these requirements. To simplify the solution, it has been broken up into small sections.
Setup
Before working on this example, you’ll need to modify a few things from the first example. You will find an application that was configured with the following modifications in the Source Code/Download area of the Apress web site at www.apress.com. You can skip this section if you import the application 08_example-2_base_application.sql.
Figure 8-30. P1_ENAME properties
Create Department Employees Report
To meet the first requirement, create a Classic Report region that lists the employees in the selected department. To create this report, follow these steps:
select e.empno,
initcap(e.ename) ename,
initcap(e.job) job,
e.hiredate,
e.sal
from emp e
where e.deptno = :p1_deptno
Figure 8-31. Region’s Source
Figure 8-32. Column formatting/HTML expression
Note The two custom attributes, data-empno and data-ename, are HTML 5–compliant custom attributes. HTML 5 supports custom attributes by prefixing the attribute name with data-. The following blog contains a brief overview of HTML 5 custom data attributes: http://ejohn.org/blog/html-5-data-attributes.
If you refresh page 1, it will look like Figure 8-33. If you change the department, nothing happens, since you haven’t applied any dynamic actions.
Figure 8-33. Department Employees report added
Refresh Department Employees Report
The first dynamic action to create is to refresh the Department Employees report when the P1_DEPTNO select list changes. The following steps will create the dynamic action when the department is changed:
Figure 8-34. OnChange True Action properties
If you refresh the page and change the department, the report should be updated. Figure 8-35 shows the page when Accounting is selected as the department.
Figure 8-35. Department Employees report updated by dynamic action
Now that the Department Employees report refreshes when the department is changed, the next step is to add the ability to highlight each row when a user hovers over it. If you inspect the CSS styles for a column in the department employee’s table when you hover over it, the style changes to Figure 8-36.
Figure 8-36. Table row hover CSS
Using the CSS definition from Figure 8-36, you can modify the CSS to highlight the row when you move it to yellow. The new CSS should look like the following code sample (where REGION_ID is the region’s ID). Adding #REGION_ID restricts the new highlight rules to just the Department Employees report.
/* Using the DEPT_EMP_REPORT id ensures that this highlighting will only affect the
Department Employees report */
#<REGION_ID> .t-Report--rowHighlight .t-Report-report tr:hover .t-Report-cell{
background-color: yellow !important;
}
Normally you would include the CSS in the page’s inline CSS area by selecting Page 1 in the left pane and then modifying its properties in the right pane. Figure 8-37 shows where to include the custom CSS. If you want to make the CSS available to the entire application, you can modify the custom CSS option in the Theme Roller, as shown in Figure 8-38.
Figure 8-37. Page inline CSS
Figure 8-38. Theme Roller custom CSS
For the purpose of this example, inline CSS will be “injected” into the application using a dynamic action.
Figure 8-39. onPageLoad Action configuration
var regionId = this.affectedElements.attr(’id’);
var css = ’#REGION_ID .t-Report--rowHighlight .t-Report-report tr:hover .t-Report-cell{ background-color: yellow !important; }’;
css = css.replace(’REGION_ID’, regionId);
$(this.affectedElements).prepend(’<style type="text/css">’ + css + ’ </style>’ );
If you refresh the page and hover over each row, you should notice that the current row is highlighted in yellow, as shown in Figure 8-40. You can change the color by modifying the value in the dynamic action’s JavaScript code.
Figure 8-40. Highlighted row
Row Click
The next dynamic action will handle what happens when a row is clicked. According to the requirements, when a row is clicked, the employee number should be set in a hidden field (P1_EMPNO), and the employee name should be displayed.
To meet this requirement, the additional custom data attributes that were added to the ENAME column in the report will be leveraged. If you inspect the HTML of an employee name in the report column, you’ll notice the additional attributes, data-ename and data-empno, as shown in Figure 8-41.
Figure 8-41. HTML 5 custom data attributes
The following steps will create the dynamic action that will handle the row click event:
Figure 8-42. onClick Emp dynamic action configuration
$(this.browserEvent.target).closest(’tbody’, this.browserEvent.currentTarget).length > 0
Figure 8-43. onClick Emp True action
//dataSpan will represent the span tag that was created earlier
//which contains the custom data attributes
var dataSpan = $(this.browserEvent.target).closest(’tr’).find(’[data-empno]’);
//Set the EMPNO and its display values using the data attributes
apex.item(’P1_EMPNO’).setValue(dataSpan.data(’empno’));
apex.item(’P1_ENAME’).setValue(dataSpan.data(’ename’));
If you refresh the page and click a row in the Department Employees region, the associated employee’s name should be displayed beside the Employee label, and P1_EMPNO will be populated accordingly, as shown in Figure 8-44.
Figure 8-44. Select Employee, row click
Once you confirm that everything is working, change P1_EMPNO to a hidden field. Since you’re modifying its value in JavaScript, change the Value Protected option on the item to No.
The displayed employee name needs to be emphasized after the employee has been selected. To emphasize the name, immediately hide the employee name, make it red, and then have it fade in. Once the fade-in is complete, remove the highlighted red color.
There are various ways to do this in dynamic actions. You could modify the existing dynamic action and append some additional JavaScript. The following steps will help highlight another type of action and how multiple actions work within a dynamic action:
Figure 8-45. Set Style action
Figure 8-46. Updated dynamic action execute order
- Action: Execute JavaScript Code
- Affected Elements > Selection Type: Item(s)
- Affected Elements > Item(s): P1_ENAME
- Fire On Page Load: No
this.affectedElements.hide().fadeIn(2000, function(){
//The second parameter in the fadeIn function allows you to define a
//function to be run once the fadeIn is completed.
//This function will be used to reset the color
$(this).css(’color’, ’’);
});
Refresh Page 1, select a department, and then click an employee in the Department Employees report. When the name appears in the Employee field, it should fade in and be red. Once the fade-in is complete, it should return to its original color (black in this example).
So far all the requirements have been met except for the modal window. Because it is easier to develop, debug, and demonstrate the example without the extra complexities of a modal window, I saved this for last.
Similar to other requirements in this example, there are several ways to implement this solution. One option would be to use the new APEX 5 modal page feature; however, it would add unnecessary complexity to the application.
Instead, this solution will take advantage of some of the features found in the new APEX 5 Universal theme. This solution will leverage the jQuery UI Dialog widget (https://jqueryui.com/dialog/), which is already included in APEX 5. This solution will use a simple command to open and close the dialog window. You can find more options in the jQuery UI Dialog API documentation: http://api.jqueryui.com/dialog/.
Figure 8-47. Modify region’s template
Figure 8-48. Template Options
Figure 8-49. Dialog open dynamic action properties
this.affectedElements.dialog(’open’);
this.affectedElements.dialog(’close’);
Refresh Page 1 to view the changes. When you change a department, the Department Employees region should appear as a modal dialog window. When you select an employee, the employee name gets updated, and the Department Employees region closes.
Summary
This chapter covered all aspects of dynamic actions, such as how to create a dynamic action and all the options available when configuring a dynamic action. The last section demonstrated several kinds of dynamic actions and how they can work with one another.