Monday, 14 December 2015

Tutorial: Include action button in report

In reality, this 'add' button could represent any action you would like in a report that would execute PL/SQL upon press of a row level button.


In this example I click on a button in a report to add the row to collection, without submitting the page.

Prepare page

Add Static id to your report region:
p2_my_report

Add hidden page item: P2_ADD
Set protected = No if you need to submit the page for other processes.

Create before header process to initialise collection
APEX_COLLECTION.TRUNCATE_COLLECTION(p_collection_name => 'EMPS');


Add link column

Define a new column in your report that will serve as the link button, it only returns null. For classic reports you could create a virtual column for the purposes of a link.


My report on emp uses this SQL
select e.*, null add_btn from emp e

Modify the new column and set the column type to 'Link'.

Set URL to: javascript:void(0);
Link text: Add
Link Attributes: data-id="#EMPNO#" class="add t-Button t-Button--warning t-Button--simple t-Button--stretch"

The data tag creates an attribute that we can interrogate easily with jQuery, returning the ID of the record.
The classes represent the same classes that would be applied when choosing relevant template options. The 'add' class is added for our dynamic action.

Create dynamic action

Create a new dynamic action that will respond to button press, using on click of a jQuery selector.


Use the following selector to identify add button clicks on your report.
#p2_my_report .add

Add an action to execute the following JavaScript. It sets the page item with the value of the ID set in the data tag.
$s('P2_ADD', $(this.triggeringElement).data('id'));

Don't forget to set this to not Fire on Page Load. this.triggeringElement represents the button pressed, which is generated as the following HTML.
<a href="javascript:void(0);" 
   data-id="7900" 
   class="add t-Button t-Button--warning t-Button--simple t-Button--stretch">Add</a>


Other JavaScript options

If other information was required, you could define more data tags, or traverse the DOM to find other values in the row. For IR you would need to first define static ID for the column as SAL. Classic reports automatically use the column alias.
$(this.triggeringElement).closest('tr').find('td[headers=SAL]').text()

If you were defining a remove function, then a second statement could be added to immediately hide the row from view without needing to refresh the report by locating the surrounding tr tag.
$(this.triggeringElement).closest('tr').hide();
Though this may make pagination feel a little strange, as the number of rows displayed won't add up.

Execute the PL/SQL

You could then define a second action that executes PL/SQL, including P2_ADD in 'Page Items to Submit', so you can then refer to :P2_ADD as a bind variable in the PL/SQL. Note, you should always explicitly convert any value from session state that is not a string.


Alternatively, you could define an onChange event on P2_ADD which does the same thing. This would allow different UI on the page to invoke the same action.



The onChange dynamic action should only execute when the item is not null, and an action after the PL/SQL should clear the item. This allows the same value to be selected successively, otherwise the value wouldn't 'change' the second time around.
In the screenshot & example below I also refresh the region containing the collection.

Outcome

So that describes a pattern I use frequently, and some variation of which is asked on the forums all the time. I plan to extend this example to include the collection report as a modal dialog with the ability to add & remove.



Run the demo to see it in action.


If you want to explore this further, you might like my book on jQuery with APEX. </shameless-plug>

4 comments:

Anonymous said...

Hi Scott,
The cover of the book that I recived looks quite different.
Hm... - I think you should (have to) exchange your's at several web locations :-)
Regards
Andre

Scott Wesley said...

I've updated the blog to use the final image, but I notice many of the online sites still use the first drafted icon. That's out of my control ;p

ruepprich said...

Nice post Scott. Just what I needed.
Thanks!

Scott Wesley said...

No worries. A favourite pattern of mine.