Closing all Popups in Flex or AIR

Posted on Feb 29, 2008

Flex makes opening popup windows a very easy task, and generally speaking closing them is simple as long as you know what type of display element they are. However, let's assume you wanted to close all popups regardless of what they are. The only current example I could find on closing all popups in Flex assumed that every popup was of the same type (nonetheless, this post was extremely helpful to me in solving this problem).

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).

Comments

julien For other needs, I wanted to have all popups, but my systemManager.popUpChildren is always empty !!! any idea ? (Flex 3)

Posted By julien / Posted on 05/12/2008 at 7:51 AM


Brian Rinaldi Not sure I understand the question but the key here is that you add them to PopUpManagerChildList.POPUP when calling addPopup (see code above). If you don't they aren't there (the flex monkey post cited above talks about where else they might be by default).

Posted By Brian Rinaldi / Posted on 05/12/2008 at 11:33 AM


Tim Bain The parsing of the classname seems unnecessarily complex, and requires that all classes implementing the interface be placed within that package. It also is a refactoring nightmare, since that package name is not checked at compile time.

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 &quot;as&quot; 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.

Posted By Tim Bain / Posted on 06/17/2008 at 8:47 AM


Brendan Lee I'm very new to Flex and in need of a way to dispatch a Close event to all my open popups. I'm thinking this code will work for that?

In each of my popups I implement the iPopup interface and I have a Private Function called closeWindow. In the closeWindow function I have my code how to close the window. But I am getting an error "Interface method closeWindow in namespace components:iPopup not implemented by class components:AddressPop" AddressPop is the name of the popup window and it is a Titlewindow.

Also, using your code and the code suggested by Tim I have this:

private function closePopups():void
{ var popupPackage:Array;var popup:iPopup;
for (var i:Number=0;i<systemManager.popUpChildren.numChildren; i++) { popupPackage = getQualifiedClassName(systemManager.popUpChildren.getChildAt(i)).split("::");
if (popupPackage[0] == "components") {
if (systemManager.popUpChildren.getChildAt(i) is iPopup)
{popup = systemManager.popUpChildren.getChildAt(i) as iPopup;
} else    {popup = null;}
}
if (popup != null) {popup.closeWindow();}}}

Have I hacked this together correctly?
Any help you can give would be greatly appreciated! Thanks in advance.

Posted By Brendan Lee / Posted on 01/28/2009 at 2:12 PM


Brian Rinaldi @Brendan - that seems ok offhand...is it working? If so, then go with it. Fwiw, I think Tim was saying you don't need to parse the classname which makes, though I haven't tried it since I don't maintain this application anymore.

Posted By Brian Rinaldi / Posted on 01/29/2009 at 6:52 PM


Write your comment



(it will not be displayed)





About

My name is Brian Rinaldi and I am the Web Community Manager for Flash Platform at Adobe. I am a regular blogger, speaker and author. I also founded RIA Unleashed conference in Boston. The views expressed on this site are my own & not those of my employer.