Skip to Main Content
  • Questions
  • Calling PL/SQL API with respect to Interactive Grids

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question, Joseph.

Asked: September 16, 2020 - 11:18 am UTC

Last updated: September 30, 2020 - 12:09 am UTC

Version: 20

Viewed 1000+ times

You Asked

Info on example apex.oracle.com example below.
I have a problem with IG I am trying to solve, have searched and posted in different forums without success, and am hoping you can point me in the right direction. If not, I understand, and please let me know. This seems to me it should be really simple, but I am completely missing it.

Objective:
- Call PL/SQL Function or Procedure that can reference current values in the active row in the Master table, or in the Detail table using a button in the grid region, a "hamburger menu" option, an action menu item, or a "dummy" column with a button/icon (I don't see how to call just a procedure from the dummy column though without calling another page).
o Examples: (Not real, just trying to illustrate desired functionality)
 PL/SQL procedure to cancel the currently selected Order: Pkg_Orders.Cancel_Order(:Order_ID,Current_Date) and refresh the values in the Order row.
 PL/SQL procedure to add an Order for the currently selected customer in the master grid, but have the button or menu item appear in the detail grid region. Pkg_Orders.Add_Order(:Customer_ID,Current_date) Add_Order procedure creates an order row, pre-populates values, i.e. checks for a recurring order template, etc. and then shows row values for edit.

Scenario:
Master-Detail interactive grid, using apex.oracle demo tables of Customers and Orders.

What I have tried:
- Add row level menu items in detail grid (code in Execute on Page Load section of Page)
- Add columns to detail table showing as an icon like you would for edit that would call another page. However, I don’t want to call another page, I just want a procedure to fire that uses values from the row they click on
- Add button item to detail region, but have been unable to reference current values from selected row.

Sample app created on APEX.ORACLE: Application 120269 – IG Master Detail Example
Workspace: valuepoint
User ID: Questions
Password: Abc4321*

Any thoughts, suggestions, or references would be greatly appreciated.

It is ok to publish when answered, but please remember to remove the workspace, user id, and password info.

THANKS!
Have a great day!
Joe

and Connor said...

I got this info from John Snyders (who looks after IG internally), so a big thanks to John.

There are 3 main parts to it.

1) Use various UI affordances to do custom processing in the context of current detail row

2) The custom processing is done in an ajax call to a PL/SQL procedure

3) Extract data from the detail row and the master row.

1 - They give many options for the UI and all are possible. In each case I recommend implementing the behavior with an action. Most of the IG examples use this method. (See interface actions https://docs.oracle.com/en/database/oracle/application-express/20.1/aexjs/actions.html ) Keep in mind that defining the action and defining the UI to invoke the action are two different steps. For IG the action is defined by adding code to Advanced: JavaScript Initialization Code. In the initActions function add the action. There are examples in the Sample Interactive Grids app on pages 5 and 53. There are also many examples in the IG Cookbook (get the cookbook here: https://hardlikesoftware.com/weblog/2019/11/04/apex-ig-cookbook-update-for-19-2/ ).

Actions often act on the selection or the current row. The example on page 53 uses an old (no longer recommended way to get the context row. It is best to use the getContextRecord method ( https://docs.oracle.com/en/database/oracle/application-express/20.1/aexjs/interactiveGridView.html#getContextRecord ). There are examples of using getContextRecord in IG cookbook pages 18, 25, 26. The general pattern is:

action: function(event, el) {
  ...
  rec = view.getContextRecord( el )[0];
  ...


To act on the selection use the view getSelectedRecords method ( https://docs.oracle.com/en/database/oracle/application-express/20.1/aexjs/interactiveGridView.html#getSelectedRecords ) or the IG method by the same name ( https://docs.oracle.com/en/database/oracle/application-express/20.1/aexjs/interactiveGrid.html#getSelectedRecords )

A nice thing about using actions is that you can define a keyboard shortcut.

UI Options

A) A button in a column. A good example of this can be found in Sample Interactive Grids page 10. Look at the SRV column. It invokes a built in action. In this customers case they would invoke the action they define (for example it might be called "cancel-order").

B) Add to the row actions menu. This is the hamburger menu in the actions column row. I don't have an example of adding to the row actions menu but it is very simimilar to adding to the selection actions menu. See page 12 of the IG cookbook for example. The general idea looks like this (add to execute when page loads):

var view = apex.region("emp").call("getViews", "grid"),
    menu$ = view.rowActionMenu$;

// add to the menu
menu$.menu("option").items.push({
    type:"action",
    action: "cancel-order"
});


C) Add to the selection actions menu. This is the one in the column header of the row actions column. It seems the customer wants to act on the row so this may not be what they are looking for. See IG Cookbook page 12 for example.

D) Add to the toolbar or toolbar Actions menu. This is possible but not ideal if you want the context of the current row.

2 - If all the custom behavior can be done with just JavaScript then they would be mostly done at this point but they want to call the server. There are 2 ways to do this.

1) is to use a DA Execute Pl/SQL Code action. This is the easiest option for most cases especially when all the inputs and outputs can be put in page or column items. The problem is this can only be done from a DA event and the above described action is not a DA.

2) Use the apex.server.process API. This gives more control and can easily be called from any JavaScript code. If they are comfortable defining a page or app process and calling this way then that is a good option.

If they want to use option 1 then they have to cause an event to be triggered from the action and define a DA on that event. If the action sets the value of a hidden page item then there is a natural change event that happens that they can use. Otherwise they can make up their own custom event.

3 - Accessing data from the current record and parent record. If the DA event is from a column item then you can just specify the column items from the same IG region in the Items to Submit attribute. A big limitation is that you can't reference columns from the parent IG region(s). And if the DA is triggered from a custom event or an event on any element outside the IG region then you can't specify columns in the items to submit. One option is to move the data that you need from the IG model into page items. This is an extra step and it negates some of the benefit of using the simpler DA Execute PL/SQL Code action.

Often all you really need is the row primary key to do any server processing. You can take additional data from the IG model record but you need to take more care that the user has not tampered with the data. If the values can be edited and you want to take in the edited values then no problem but if you need to make sure that the values have not changed then putting them in a page item first is not as safe.

To get around the limitation of not having access to data in the parent IG you can duplicate that data in the detail IG as hidden columns. This is wastefull of bandwidth and client memory but may be considered worth it in some cases.

If they want to use a DA and only need the detail record primary key then my suggestion is similar to Jayson's except I would define an action and put the $s inside the action function taking the primary key from the model record. I would use a column button (UI option A)

If they need more data from the detail and master records then I would define an action that uses apex.server.process to call a page or app process.

Note that unlike tabular forms, IG does not currently have the option to submit selected rows (it only sends the rows that have *changes*).

One way to work similar to the way tabular forms did is to define a button outside the IG region (e.g. "Cancel Order") that sets a hidden column of the selected rows to say "C" for cancel. This means that the row is now changed and will be submitted. Then the button submits the page. This can all be done from a dynamic action. (Beware bug 25891453 and use its workaround to set a hidden column.)


Rating

  (1 rating)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Helpful content, example would be helpful

Joe Kerr, September 30, 2020 - 11:23 am UTC

Thanks for pulling the content together. It is good coverage of possibilities and the issues. Could you provide one complete example? It would be very helpful.
Thanks
Joe

More to Explore

APEX

Keep your APEX skills fresh by attending their regular Office Hours sessions.