HowToUseCairngormPopup

How to use the Cairngorm Popup Library

Contents

Summary

The Cairngorm Popup library contains components for managing the opening, closure and general behavior of popups. They are designed to minimize Script-block logic in MXML components and to reduce code duplication across applications that manage multiple popups.

Release Notes

Changes in Version 1.12:

  • Exposed set accessor of open for view state usage and fixed bug when closing from model within popup.
  • Added Spark version of ZoomAndFadeBehavior.
  • Added behaviors behind "cairngorm" namespace to protect for future packaging changes.

Introduction

The Cairngorm Popup library is a small Flex library for opening and closing popups. Instead of using the PopUpManager directly and writing script-block logic to manage their creation and removal, a pair of simple MXML tags are available for declaring within view components. Here's the "Hello World" of declarative popups:

<cairngorm:PopUpWrapper open="{model.openPopUp}">
    <mx:Label text="Hello World"/>
</cairngorm:PopUpWrapper>

The PopUpWrapper tag is a non-visual component that manages opening and closing the popup. When its open property is set to true, a popup is opened containing the component wrapped by the tag; in this case a Label. When the open property is set back to false, the popup closes again. Alternatively, the component may dispatch an Event.CLOSE event, which will be handled by the PopUpWrapper itself.

This approach helps to keep MXML views components clean and free from ActionScript logic, whilst removing duplicated code wherever the PopUpManager is needed. The opening and closure can be controlled conveniently through bindings, as above, which plays nicely with Presentation Model. There are also simple ways to control the life-cycle of the popup and to apply special behaviors, such as effects that play while it opens and closes.

The remainder of this post covers the two components available – PopUpWrapper and PopUpFactory – explaining the differences between them. The source code, unit tests and a sample application are available for download from the Adobe Open Source SVN.

Using Declarative Popups

Developers using SDK 4:

Since Flex SDK 4 was released, the PopUpFactory component is deprecated as SDK 4 provide a new interface for deferred instantiation. The ITransientDeferredInstance extends IDeferredInstance and add the ability for the developer to reset the deferred instance which make the PopUpFactory redundant with PopUpWrapper.

  • PopUpWrapper - By default it defers the creation of the popup view until the first time the popup is opened. The view is made eligible for garbage collection upon closure. If the reuse property is set to 'true', the component will reuse the same view every subsequent time it is opened.
Developers using SDK 3:

There are two components with slightly different capabilities:

  • PopUpWrapper - this is the simplest tag. It defers the creation of the popup view until the first time the popup is opened, then reuses the same view every subsequent time. There is no mechanism for releasing that view to be garbage collected.
  • PopUpFactory - this is the more flexible but less simple tag. It also defers creation of the popup view, but gives control over whether or not the view should be reused when the popup is next opened. If reuse is disabled, the view is made eligible for garbage collection upon closure.

Some examples of each are now provided.

The PopUpWrapper Component

Here's a more detailed version of the "Hello World", this time showing all of the properties and events available:

<cairngorm:PopUpWrapper
    open="{model.openPopUp}"
    center="true"
    modal="false"
    childList="{PopUpManagerChildList.POPUP}"
    opening="openingHandler()"
    opened="openedHandler()"
    closing="closingHandler()"
    closed="closedHandler()"
    reuse="true">
    <mx:Label text="Hello World!"/>
<cairngorm:PopUpWrapper>

The properties provide the same control over the popup as the PopUpManager.
Please note that the reuse property is only available in the SDK 4 version of the library

The events are dispatched at various points during the life-cycle of a popup:

  • PopUpEvent.OPENING is dispatched after the popup view has been created but just before it has actually been added to the display list.
  • PopUpEvent.OPENED is dispatched just after the popup view has been added to the display list.
  • PopUpEvent.CLOSING is dispatched just before the popup view is removed from the display list.
  • PopUpEvent.CLOSED is dispatched just after the popup view has been removed from the display list.

Here's another example where the popup is opened or closed using buttons instead of binding. The view used for the actual popup is a custom component.

<cairngorm:PopUpWrapper id="popup">
    <mypopup:MyPopupView/>
</cairngorm:PopUpWrapper>

<mx:Button label="Open"
           click="popup.open = true"/>
<mx:Button label="Close"
           click="popup.open = false"/>

The popup view itself can also instruct the closure of the popup by dispatching an CloseEvent.CLOSE event. For example:

<mypopup:VBox...>
    <mx:Label text="My Popup!"/>
    <Button 
        label="Close" 
        click="dispatchEvent(new CloseEvent(CloseEvent.CLOSE))"/>
</mypopup:VBox>
The PopUpFactory Component (Flex SDK 3 only)

Please note that the PopUpFactory is deprecated in the SDK 4 version of the library

The PopUpFactory tag uses a different mechanism for specifying the popup view. It is in fact the same approach that list-based controls use for their item renderers. The factory property can either be set to the class name for the popup view, or else an in-line component can be declared. Here is a simples use case, specifying the popup view class name:

<cairngorm:PopUpFactory open="{model.openPopUp}"
                    factory="my.package.MyPopupView"
                    reuse="false"/>

Notice that the PopUpFactory includes a reuse property. This gives control over whether or not the popup view is reused, in contrast to the PopUpWrapper tag which always reuses the view and never makes it eligible for garbage collection.

When working with the PopUpManager directly it is common to make popups eligible for garbage collection once they have been removed. However there are good use cases for both approaches. If an application shows a large popup at start-up and then never again, it is wasteful of resources to keep it in memory. Alternatively, if a popup is repeatedly shown and hidden, such as a context menu, it is more efficient to reuses a single instance. As with all Flex development, the Flex Profiler should be used to ensure popup views are successfully garbage collected, since they can be a source of memory leaks.

Here is another example where the popup view is declared as an in-line component, in a similar manner to an item renderer on a list-based control.

<cairngorm:PopUpFactory open="{model.openPopUp}"
                    reuse="false">
    <mx:Component>
        <mypopup:MyPopupView title="{outerDocument.model.popUpTitle}"/>
    </mx:Component>
</cairngorm:PopUpFactory>

The PopUpFactory tag also provides the same properties as the PopUpWrapper tag, since they both inherit from a common base class.

Popup Behaviors

It can be common to customize how popups behave. In one situation, a popup might need to play a transition while opening; in another a popup might have to remain centered whenever its contents resize.

The IPopUpBehavior interface was introduced to extract these specialities into their own classes. In this way, a set of behaviors can be created, independent of one another, and the appropriate behaviors can be applied for a given situation. This design creates a nice extensibility point, allowing developers to write their own behaviors without needing to customize the declarative tags at all.

Here is an example of a popup with a number of behaviors applied.

    <cairngorm:PopUpWrapper id="popup1"
        popup="samples.MyPopup"
        modal="{cb.selected}">
        <cairngorm:behaviors>
            <cairngorm:KeepCenteredBehavior/>
            <cairngorm:ZoomAndFadeBehavior/>
        </cairngorm:behaviors>
    </cairngorm:PopUpWrapper>

In this case, two custom popup behaviors are being applied. The first plays a zoom and fade effect upon opening and closure, while the second ensures that the popup remains centered whenever its contents is resized. The declarative approach makes it simple to configure these behaviors.

To write your own popup behavior, just implement the IPopUpBehavior interface:

public interface IPopUpBehavior
{
    function apply(opener:PopUpBase):void;
}

A reference to the popup component is passed through the apply() method to each behavior. The behavior can then attach event handlers in order to control the behavior of the actual popup while it is opened or closed. Some examples are provided in the sample project (download above). A behavior can also suspend and resume closure by calling the suspendClosure() and resumeClosure() methods of the PopUpEvent class. This allows something asynchronous, such as the playing of an effect, to take place during closure, before the popup is actually removed from the display list.

How Does It Work?

The design for the popup tags is relatively simple. There's a common base class – PopUpBase – that is extended by the two tags: PopUpWrapper and PopUpFactory . The base class contains the common properties – open , center , modal – and also holds an array of behaviors, applying them during opening and closure. The two concrete tags implement different creation and destruction policies using the standard mechanisms for deferred instantiation and object factories: IDeferredInstance and IFactory . The Flex compiler takes care of the rest, converting the declared popup view into an appropriately configured DeferredInstanceFromFunction/Class or ClassFactory object. See the Flex Language Reference for more details.

Usage with Parsley

Note: With Parsley 2.3.1 and Flex 4, we recommend to use the Parsley PopUp tag instead of the PopupParsley library and it's Parsley related behaviors.

While the Popup library is not dependent on the Parsley Application framework, it can be used in combination with it. The opening and closing events of the PopUpWrapper and PopUpFactory can be listened to, in order to add and remove popup views to Parsley's ViewManager. The PopupTest library offers a behaviour for this task:

<cairngorm:behaviors>
    <mx:Array>
        <parsley:AddPopUpToParsleyContext/>
    </mx:Array>
</cairngorm:behaviors>

This example of the PopUpTest project showcases more. For more information on why Parsley requires this extra step, please refer to the official Parsley documentation under Dynamic View Wiring.

Conclusion

We've been using versions of these tags on our projects for several years now. They help us to separate concerns, keeping our views as simple declarations of components, free from script block logic that would make them harder to understand and more difficult to unit test.

It's worth noting that Flex 4 includes its own declarative tag – PopUpAnchor – which also takes advantage of MXML and deferred creation, but it is designed for drop-down menu scenarios. There are some similarities, but the PopUpWrapper and PopUpFactory components are designed for more general popup handling. Perhaps a future version of the SDK will include declarative tags that make it simple to manage the life-cycle of popups and apply different behaviors, but in the meantime we hope you enjoy using these components.

### Cairngorm 3 - [ Home ][1] - [ Guidelines ][3] - [ Tools ][4] - [ Libraries Downloads ][2]
### Cairngorm 2 - [ Home ][5] - [ Framework Downloads ][6] - [ Eclipse Plugin ][7]
### Project - [ Source ][8] - [ Bug Database ][9] - [ Submitting a Patch ][10] - [ Developer Documentation ][11] - [ Forums ][12] - [ License ][13]