Menu Popup with Declarative List
In the past when I’ve needed to add half a dozen or more buttons to a page, I’ve sometimes encased them in a Collapsible region so that the user can slide them out of the way instead of clogging up the screen. Recently however I’ve started (sparingly) using a Menu Popup, as per this tutorial. The issue I have with this method, however, is that the menu items are defined in a shared component (a List) which means it’s not defined on a per-page basis.
Some of the actions simply need to do a Submit on the page, which is simple enough: set the URL Target to something like:
In other cases, the action needs to do something more specific to the page, e.g. show a region:
apex.theme.openRegion("popupQuestion")
Or the action might need to navigate to another page, passing parameters based on specific items on the page. This means the list, defined in Shared Components, now has hardcoded elements that are only useful for that one page; more to the point, they are defined outside of the page – I’d rather that everything specific to a page is defined within that page’s definition.
The approach I’m using now is to use a custom trigger. Each list item has its URL Target set to something like:
The third parameter is set to a unique code that the page can use to identify which menu option was chosen. This parameter will be passed to this.data
in the custom trigger’s event handler.
On the page, I have a Dynamic Action with the following attributes:
- Event: Custom
- Custom Event:
menuAction
- Selection Type: JavaScript Expression
- JavaScript Expression:
document
- True Action: Execute JavaScript Code, e.g.:
switch(this.data) {
case 'OPEN_POPUP':
apex.theme.openRegion("popupQuestion");
break;
default:
apex.submit({request:this.data,showWait:true});
}
Note that to do a simple Submit on the page, all I need to do is set the request on the third parameter of the menu item’s URL. If I want to do something slightly different for a particular request, I can put an extra “case” in the JavaScript code to handle it.
The benefit of this approach is that this trigger becomes the jumping-off point for all such menu actions for this page. In theory I could re-use the same List on multiple pages (if the items in the list are generic enough) but have different behaviour occur for each menu item specific to each page. The only challenge with this approach might be if you needed some conditions on each menu item, e.g. so they are shown or hidden in specific circumstances. If the condition for a menu item references a particular page item the List will no longer be generic and re-usable. For this reason, I usually still use a separate List for each menu for each page.
Perhaps in a future release of APEX we will gain the ability to define a List on a Page instead of in Shared Components. In the meantime, if you are interested in all the details on this method (including a solution for implementing a redirect to another page, or to open a modal page), refer to this tip.
EDIT 22/8/2019: Thanks to Robert Gerstein who noticed an issue with this solution when using Internet Explorer. A workaround for this is to not call apex.event.trigger directly in the URL on the list item, but to call a function instead (refer to comments below).
Juergen
14 August 2019 - 5:11 pm
Love the idea
Learco
16 August 2019 - 3:12 pm
Hi Jeff,
Nice approach.
Is a Dynamic List also an idea? You could use a function in the query to get page specific URL Targets, etc.
Jeffrey Kemp
16 August 2019 - 3:22 pm
Hi Learco,
Thanks for your comment. Yes, that would work and may well be a good approach in some cases.
However, I don’t consider that a sufficiently “declarative” method which is what my goal here was. Also, it’s still defined in Shared Components, away from the page. This is not to say it’s a bad idea though.
Jeff
Robert Gerstein
22 August 2019 - 12:49 am
Great but…
I’m having an issue with IE 11 (which I have to use due to company policy).
My menu choices all issues a window.alert (‘You selected Menux’);
but when I get the alert and click OK, it sends false to the page.
The JavaScript in the DA is:
debugger;
switch(this.data) {
case ‘MENU1’:
window.alert (‘You selected Menu1’);
break;
case ‘MENU2’:
window.alert (‘You selected Menu2’);
break;
case ‘MENU3’:
window.alert (‘You selected Menu3’);
break;
case ‘MENU4’:
window.alert (‘You selected Menu4’);
break;
case ‘OPEN_POPUP’:
apex.theme.openRegion(“popupQuestion”);
break;
default:
apex.submit({request:this.data,showWait:true});
}
When I test it with Google Chrome, it works fine.
Jeffrey Kemp
22 August 2019 - 9:25 am
Hi Robert,
Thanks for that. I’ve reproduced the problem at my end as well. Looks like this is a known issue with Internet Explorer – refer https://stackoverflow.com/questions/47399518/internet-explorer-returns-false?noredirect=1&lq=1
I don’t know a solution at this time but I’m going to have to find one as my customer also standardises on IE.
Jeff
Jeffrey Kemp
22 August 2019 - 10:41 am
Hi Robert,
I’ve found a workaround. Instead of calling apex.event.trigger directly from the list, I add a function the page or application and call that instead. e.g. add this to the Function and Global Variable Declaration, or to an application-wide javascript file:
function menuAction(req) {
apex.event.trigger(document,'menuAction',req);
}
Then, set the URL for the list item to:
javascript
:menuAction('COPY')
(Note: the above is all on one line)