Creating a Popup in a Cairngorm Architecture

Often I see this question coming up:

“How should I best create a popup in my Cairngorm application?”

I think of creating a popup control as something only views should be concerned about. It’s like creating other view components, managing states of view components or effects. Therefore this question isn’t just about creating popups, instead it’s about how to invoke methods that belong to the view. (BTW: I often hear from our User Experience team that they try to prevent popups where possible)


First and foremost, I’d try to let your views directly call a method that dispatches a popup.
However, most of the use cases that came up when questions like the above have been asked are slightly more complex. Users for example want to create a popup in a completely different part of the application. Or they receive an asynchronous remote service response, only want to react to the user with a popup at that point in time and work in a context where no view references are available, such as a typical Cairngorm Command.
Some users have created the code needed for creating a popup directly in the result method of a command or in a model object that’s been called by the result method of a command.
Sticking to my above rule; that only views should be concerned about popups, I think both solutions are not the optimal approach. A command should just be an encapsulated request to your model and a model itself should also not be concerned about any UI behavior. I’d argue we need to tell the model about the state change that has just occurred in your application, but in a model context. For example you might set a loggedIn property on a Login model object to true in order to signal that the login process was successful after a positive remote service response.
So, how can our views react to that state change in our model?
In a typical Cairngorm application, we may bind UI controls to properties of our model objects. But for creating a Popup control, there’s no UI component where we can bind to. How do we best let a view invoke a view related method after a certain state change in our model occurred?
Let’s take a step by step approach using a very simple Cairngorm application, that retrieves a list of employees and displays them in a popup after successful retrieval.
Please do ask your UX team if something like this is really a good idea in a real world application. For the sake of this example we don’t care about the user experience here!
This step by step tutorial will walk you through the relevant parts. You can see and download (via right click > View Source) the complete application here. Let’s go:
Dispatch a Cairngorm Event.
Let the view dispatch a user gesture via a Cairngorm Event in order to trigger the remote service:
On a mx:Button’s click event, the getEmployees method dispatches the Cairngorm event:
Excerpt from GetEmployeesCommand.as:

private function getEmployees() : void
{
var event : GetEmployeesEvent = new GetEmployeesEvent();
event.employees = model.employees;
CairngormEventDispatcher.getInstance().dispatchEvent( event );
}

Call and handle the remote service and modify your model.
The handling GetEmployeesCommand’s execute method calls a server side method. Its result method modifies the model. Here, it retrieves the model object Employeee via the ModelLocator.
Excerpt from GetEmployeesCommand.as:

private var employees : Employees;
public function execute( event : CairngormEvent ) : void
{
employees = GetEmployeesEvent( event ).employees;
employees.hasEmployees = false;
var delegate : EmployeeDelegate = new EmployeeDelegate( this );
delegate.getEmployees();
}
public function result( event : Object ) : void
{
employees.employees = IList( event.result );
employees.hasEmployees = true;
}

Employees.as:

package com.adobe.cairngorm.samples.popup.model
{
import mx.collections.IList;
public class Employees
{
[Bindable]
public var employees : IList;
[Bindable]
public var hasEmployees : Boolean;
}
}

Note that we modify the hasEmployees property of the Empoyees model object.
Let the view react react for you!
And here comes the crux: You can use the mx:Binding tag or the Observe/ObserveValue tag to invoke a view method, once the hasEmployees Boolean value changes.
I’d recommend using the ObserveValue tag to listen to a specific value of a state change of your model. More precisely, you can bind the source property of it to the bindable hasEmployees property of your model object Employees.

<ac:ObserveValue
source="{ model.employees.hasEmployees }"
handler="{ createEmployeeList }"
value="{ true }"/>

You could have also used the Observe tag to listen all updates of the hasEmployees property. For more information, check this out.
The ObserveValue tag above will invoke the createEmployeeList method defined in a Script block of the same MXML file. This method will invoke the popup.

private function createEmployeeList() : void
{
var application : DisplayObject = DisplayObject( Application.application );
var popup : IFlexDisplayObject = PopUpManager.createPopUp( application, EmployeeList, true );
PopUpManager.centerPopUp( popup );
var concretePopup : EmployeeList = EmployeeList( popup );
concretePopup.employees = model.employees;
}

That’s it! Through a state change in your model, you view has reacted. Furthermore, you can now let many other objects observing this particular state of your model and they can all act independently.
Cheers!