Closing all Popups in Flex or AIR
I am building a proof-of-concept application using Flex and AIR. In this application I use the code for minimizing to the system tray whereby it asks if you want to close the application or minimize when you click on the close button. Unfortunately, if a modal popup was already open, the Alert would appear underneath it. What I wanted was simply to close any open windows and then open the Alert, and here's how I did it...(keep in mind I am still learning Flex so, you Flex gurus, feel free to suggest improvements)The first thing to note, as discussed in the Flex Monkey post, is that when I am creating popups, I am adding them to the PopUpManagerChildList.POPUP like so:
mx.managers.PopUpManager.addPopUp(myPopup,this,true,PopUpManagerChildList.POPUP);
This isn't a requirement but makes it easier to retrieve all popups later on when we wish to close all windows.
Each MXML component I am using for my popup displays live within the /com/view folder. Each of them also implement an interface I created called iPopup which also lives within the /com/view/ folder. For example:
<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="410" height="340" title="Employee Detail" creationComplete="loadImage()" implements="com.view.iPopup">
The interface only enforces a method called closeWindow() which allows each window to manage how it closes (for instance one executes an animation when it closes, though it appears that with the focus being lost on the Alert the animation is not visible). Here is the code for the iPopup interface:
package com.view { import mx.core.IFlexDisplayObject; public interface iPopup extends IFlexDisplayObject { function closeWindow():void; } }
Now within my root MXML file I have a function called closeAllWindows() that loops through the children in systemManager.popUpChildren and calls the closeWindow() function. However, in investigating this, it looks like when each of these popups are opened, two children are added. One child is of the type of my display component (ex. com.view.MyPopup) and the other is of type mx.core.ModalWindow. Thus, if I looped through indiscriminately I would get runtime errors since my popup child could not be cast as an iPopup. To get around this, I decided to get the class name and parse it for the package whereby any class within com.view would be cast as an iPopup and the closeWindow() function would be called. Here's the code for closeAllWindows():
private function closeAllWindows():void { var popup:iPopup; var popupPackage:Array; for (var i:Number=0;i<systemManager.popUpChildren.numChildren;i++) { popupPackage = getQualifiedClassName(systemManager.popUpChildren.getChildAt(i)).split("::"); if (popupPackage[0] == "com.view") { popup = systemManager.popUpChildren.getChildAt(i) as iPopup; popup.closeWindow(); } } }
Finally, I simply called my closeAllWindows() function within the closingApplication() function within the standard system tray code.
private function closingApplication(event:Event):void { //Don't close, so prevent the event from happening event.preventDefault(); closeAllWindows(); //Check what the user really want's to do Alert.yesLabel = "Close"; Alert.noLabel = "Minimize"; Alert.show("Close or minimize?", "Close?", 3, this, alertCloseHandler); }
Anyway, everything worked well using this method. In theory I could have n number of popups open of n types and it would close all of them as long as a) they all reside within com.view (obviously this could be expanded as needed) and b) they all implement the iPopup interface. As I said earlier, the close animation on one of the popups seems not to run though I think it is because it loses focus to the Alert (again...not a Flex guru...yet).
The proper (and much simpler) solution would simply be to test whether the popup implements the interface. The easiest way to do this is to use the "as" operator (as you've done in your sample) to perform the cast if the object is of the iPopup type, or set the variable to null if it is not of that type:
popup = systemManager.popUpChildren.getChildAt(i) as iPopup;
This equates to the following code:
if (systemManager.popupChildren.getChildAt(i) is iPopup) {
popup = iPopup(systemManager.popupChildren.getChildAt(i));
} else {
popup = null;
}
Then all you have to do is test for null before calling your closeWindow() method:
if (popup != null) {
popup.closeWindow();
}
So the only change needed is to wrap your popup.closeWindow() call in the null check, and you can eliminate the hack to get the package name.

