MAF Version: 2.1
Problem
Statement
In MAF, application
developers use two component behavior tags, amx:showPopupBehavior and amx:closePopupBehavior, to show or hide popup dialogs in
response to user interaction, pressing a command button or link. What however
if you need to show or hide a popup from Java in a value change listener or
similar component event? And what if the dialog should close itself after a
period of time? By the time of writing, no API for this exists in MAF.
The Solution
Since there is no
framework API to close and open popup dialogs in MAF, a custom implementation must do. The custom implementation uses JavaScript, as well as the amx:showPopupBehavior and amx:closePopupBehavior tags on hidden buttons (visible
buttons would be possible too).
To show or hide a popup dialog you use Java in
a managed bean to call out to JavaScript,using the AdfmfContainerUtilities.invokeContainerJavaScriptFunction() framework method.
Section Q&A:
Q1: Could you call the
same from a POJO Data Control?
A1:Yes you can.
Q2: Does it make sense?
A2: No. The data
control is part pf the MAF model and thus needs to be generic and not
specifically written for a view in MAF.
About
the Example Code
The MAF 2.1 sample
code shown in this blog entry (and available for download) keeps it simple. The
AMX page displays single command button that, when pressed, triggers a
component action event. This action event is calls a Java method in a managed
bean that in turn invokes JavaScript to "virtually" press the hidden
button with the amx:showPopupBehavior tag attached to it for you. A timer in
the same managed bean then waits for 5 seconds before it closes the dialog,
pressing the other hidden button (it actually raises a tap event on teh
button). Its a simple example that however showcases nicely how you can open
and clode dialogs in MAF.
The
Sample Implementation
Though you can
download the sample ZIP file from a link provided at the end of this article,
its worth showing the code in the blog entry as well, so you you can quickly
scan it. The JavaScript source is saved in a stand-alone JS file so it can be
reused. In general I recommend using external JavaScript files and force
yourself to write generic code than to stuff scripts into an AMX page directly.
Step 1) Creating the
JavaScript file
First you need to create JavaScript file – or extend an
existing file – with the JavaScript code shown below. In my sample (MAF 2.1)
this the JS file is named "PopupUtils.js". The two functions in the
file popupUtilsShowPopup
and popupUtilsHidePopup become
globally available for the feature they are configured for (explained next).
The two functions require a singel argument to be passed, which is the id of
the popup dialog to close
(function () {
//register
popupUtilsShowPopup = function() {
//the argument is required and cannot be missing
if (arguments.length > 0) {
var popupOpener = document.getElementById(arguments[0]);
if (popupOpener != null && popupOpener != undefined) {
adf.mf.api.amx.triggerBubbleEventListener(popupOpener,"tap");
}
else {
adf.mf.log.Application.logp(adf.mf.log.level.WARNING,
"PopupUtils", "showPopup", "hidden button to launch
popup not found");
}
}
else {
adf.mf.log.Application.logp(adf.mf.log.level.WARNING,
"PopupUtils", "showPopup", "Missing input argument");
}
}
popupUtilsHidePopup = function() {
//the argument is required and cannot be missing
if (arguments.length > 0) {
var popupCloser = document.getElementById(arguments[0]);
if (popupCloser != null && popupCloser != undefined) {
adf.mf.api.amx.triggerBubbleEventListener(popupCloser,"tap");
}
else {
adf.mf.log.Application.logp(adf.mf.log.level.WARNING,
"PopupUtils","showPopup", "hidden button to close popup
not found");
}
}
else {
adf.mf.log.Application.logp(adf.mf.log.level.WARNING,
"PopupUtils", "hidePopup", "Missing input argument");
}
}
})();
Step 2) Registering
the JS file with a MAF feature
To register the JavaScript file with a MAF feature, open the
maf-feature.xml
file (the file resides in the View Controller| Application Sources || META-INF
directory). In the opened maf-feature.xml file, select the feature that needs
programmatic access to a popup and select the "Content" tab. Click
the green plus icon next to the "Includes" label and search for the
JavaScript file in the project. The file type should be set to
"JavaScript".
With this configuration, the custom JavaScript
functions become available so they can be called from AdfmfContainerUtilities.invokeContainerJavaScriptFunction()
Step 3) About the
Managed Bean (Java)
A managed bean is useed to hold the Java code that either
launches or closes the popup. The managed bean doesn't hold state and therefore
can be defined in any scope (shorter scopes are preferred). The sample actually
shows and hides the popup in response to an action performed on another button.
However, you can call the same code from any other component event, e.g. from a
value change listener.
public class PopupHelper {
boolean isPopupOpen = false;
public PopupHelper() {
}
public void onPopupShowHideAction(ActionEvent actionEvent) {
if (!isPopupOpen) {
//the error object is filled with the reason for a JS exception.
//If the variable is empty, no exception has occured. Note that
//usually you use the return object to pass information from the
//JS function back to MAF. In this case, the function doesn't
//return a value and so its only used here to allow debugging
//of exceptions
Object errorMsg =
AdfmfContainerUtilities.invokeContainerJavaScriptFunction
(FeatureContext.getCurrentFeatureId(),"popupUtilsShowPopup",
new Object[] {"_popShowId" });
isPopupOpen = true;
//wait a few seconds and then close the popup
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
closePopup();
this.cancel();
}
},5000);
}
}
private void closePopup() {
if (isPopupOpen) {
Object errorMsg =
AdfmfContainerUtilities.invokeContainerJavaScriptFunction(
FeatureContext.getCurrentFeatureId(),"popupUtilsHidePopup",
new Object[] {"_popCloseId" });
isPopupOpen = false;
}
}
}
Step 4) Configuring
the hidden buttons
The hidden buttons
(in this example they are hidden, but can be visible too) have the two behavior
tags, amx:showPopupBehavior and amx:closePopupBehavior defined as shown in the
AMX page source shown below
<amx:panelPage>
…
<amx:commandButton text="_hiddenShow" id="_popShowId"
inlineStyle="visibility: hidden;">
<amx:showPopupBehavior id="spb1" popupId="p1"
type="action" decoration="simple" alignId="pp1"
align="overlapMiddleCenter"/>
</amx:commandButton>
<amx:commandButton text="_hiddenClose" id="_popCloseId"
inlineStyle="visibility: hidden;">
<amx:closePopupBehavior id="cpb1" popupId="p1"
type="action"/>
</amx:commandButton>
<amx:commandButton text="Show / Hide Popup" id="cb3"
actionListener="#{PopupHelper.onPopupShowHideAction}"/>
</amx:panelPage>
<amx:popup id="p1" autoDismiss="false"
inlineStyle="font-size:large;">
<amx:outputText value="This Popup is launched from Java in a
managed bean. Wait 5 seconds for Java to close
this dialog." id="ot2"/>
</amx:popup>
Download
Sample
The sample files can
be downloaded in a MAF 2.1 workspace from here:
http://www.oracle.com/technetwork/developer-tools/adf/learnmore/programmaticcloseofpopup-2420222.zip Run the AMX page within the sample workspace and press the command button in
the opened mobile application. A dialog shows and stay up for 5 seconds before
it closes down again.
Note: If you experience problems, or like
to comment on the solution, please post to the MAF forum on OTN:
https://community.oracle.com/community/oracle-mobile/oraclemaf/content?customTheme=otn
