Cairngorm Sample – How Business Logic Can Manage Views Part IV

In the last post about this topic, I’ve added some functionality and another use case to our stock quote application and showcased how a Cairngorm application could scale with focusing on creating model objects. In this post I’ll perform some further refactorings to our model objects.
Furthermore, our customer wants us to show a pop-up as soon as a successful stock purchase is being made. I’ll cover how a state change in your model can transparently cause view related code (like creating a pop-up) to be executed.

Iteration 6 – Refactorings
In iteration 5 we had a statusMessage field in both model objects, StockQuote and StockPurchase. Two separate text input fields have listened to these properties. Now, let’s only have one status message for both model objects. This i.e. could bring us to the idea of creating another object that encapsulates StockQuote and StockPurchase. Let’s call it StockTransaction:

package com.adobe.cairngorm.samples.dashboard.model
public class StockTransaction
public var stockQuote : StockQuote;
public var stockPurchase : StockPurchase;
public var status : int;
public function StockTransaction()
stockQuote = new StockQuote();
stockPurchase = new StockPurchase( stockQuote );

Note that in the above, I’ve changed the previous statusMessage property; which was typed as a String, to a status property; which is typed as an int. I’ve done that so our model objects can only be concerned with a status of our use case and not with the presentation of this status. I think the presentation of the status is something that our views should be responsible for.
Our model objects can contain the different status options they can be in. i.e. our new StockQuote object can have an ERROR and a SUCCESS status, showing that the StockQuote retrieval was either successful or not. So, we can define the states with two values.

public static const ERROR : int = 1;
public static const SUCCESS : int = 0;

In our new GetStockQuoteCommand we can decide in what state the StockQuote object is currently in. Here’s a snippet of it:

public function onResult( event : * = null ) : void
//for demo purpose: event would normally be an event object of remote service result.
stockTransaction.stockQuote.lastStockQuote = event as Number;
stockTransaction.stockQuote.isPending = false;
stockTransaction.status = StockQuote.SUCCESS;
public function onFault( event : * = null ) : void
stockTransaction.stockQuote.lastStockQuote = NaN;
stockTransaction.status = StockQuote.ERROR;
stockTransaction.stockQuote.isPending = false;

There are various ways to achieve a similar separation of concerns. In this application however, I’ll let the StockMarketPod.mxml view listen to the value of status and depending on the status value, StockMarketPod will display a String, which is defined on this view. StockMarketPod uses a helper class called StatusMessageFormatter that translates the status property into the correct String needed by the view. This helper class is initialized like this:

statusMessages="{ [ '', 'Quote retrieval error.', 'Purchase error.', 'Purchase succesfull.' ] }"/>

I listen to the status via a function binding on the status property. For more information on this you can take a look into the full source code for this application at the end of this post.
Flex 2 make it easy to perform refactorings like this. This is very important since refactorings of your model objects can occur all the time and most often you rarely get it right the first time around. 😉
Iteration 6 – Invoking View Related Methods
As said in the beginning of this post, our customer wants us to alert the user via popup when a stock purchase request has successfully been made. Let’s think of creating a simple Alert window (mx.controls.Alert). When the onResult handler of the PurchaseStockCommand is invoked we know a stock purchase has been completed.
I think of creating an Alert control as something only views should be concerned about. It’s like creating other view components, managing states of view components or effects. I think only views should be responsible. Usually we bind UI controls to properties of our model objects. But for creating an Alert 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?
I basically see two ways to do this from a model. We could manipulate a model object so it dispatches an EventDispatcher event that the view can listen to. We could also just mark properties of our model as Bindable and let our views subscribe to either a custom event name that you have defined in our Bindable metadata (with [Bindable(event="customEventName")]), or to the default “propertyChange” event. Using the propertyChange event your view’s event handler method would have to differentiate what property changed. You can do that with the passed in object. Listening to a custom event name defined in the Bindable metadata, we have to dispatch the event manually using dispatchEvent.
I see two drawbacks using this approach. First of all, it’s more code to write and most importantly, to read. This is because your views need to subscribe manually to events and define event handlers. It might also affect your models since some of them might need extra EventDispatcher functionality. Secondly, we need to make sure that our model objects exist when the view is subscribing to the event.
The latter is something binding gives us for free. We can bind to a state change of a model even if the model isn’t initialized at the time of subscription. Furthermore, using the binding approach is just quicker to do in many cases.
Following the binding approach, we can bind to a property of our model objects and invoke a method in our views with using the mx:Binding tag.
This could look like the below:

private function set createChargedMessage( value : Boolean ) : void
if( value ) "Thanks! Your bank account has been charged" );

Now, instead of using mx:Binding I recommend that you use an extended version of the Observe tag that Paul Williams originally blogged.
This can make your code more secure, and furthermore it does also give you a slightly easier API to solve the problem here. We only need to listen to the “true” value of the isComplete Boolean. Therefore, we tell our new utility exactly this.

source="{ stockTransaction.stockPurchase.isComplete }"
handler="{ createChargedMessage }"
value="{ true }"/&gt

The createChargedMessage will be reduced to this:

private function createChargedMessage() : void
{ "Thanks! Your bank account has been charged" );

For more information on why I’ve introduced this utility class, please read the follow up post on this topic, “Using Binding Securely”.
What have we done here?
We needed our view to invoke a view related method based on some state change in our model. First, we’ve changed the state in the model with invoking a Command. The Command located our model object via ModelLocator and changed the state of this model object via its API. Because our view subscribed to this specific state change (via binding in our case), it could react to it with invoking a method. Since it was using mx:Binding, we didn’t need any extra ActionScript to setup the binding, neither did we need a MXML component that would accept a return value (which we didn’t have since we were calling a popup).
As I’ve noted above, there’s also one little drawback on how we use the binding approach here.
For more information on the drawback and a solution to it with an additional feature please read the next post, “Using Binding Securely”
As after every post in this series, you can view the application and download the source code of it via right mouse click > View Source.

13 Responses to Cairngorm Sample – How Business Logic Can Manage Views Part IV

  1. Dreamer says:

    Great Articles~~
    I am a newbie and learn a lot about Cairngorm.

  2. k11 says:

    Thank you Alex!
    One thing. Can you please explain one thing: where do you use public static VAR and where CONST?

  3. AlexU says:

    Hi k11,
    I’d assign the const keyword (constant) for properties that should not be changed at runtime. In the code above, I’ve used the var keyword on the class properties ERROR and SUCCESS but this was my mistake. I’ve changed this now to const, since I don’t want to allow anybody to change these values at runtime.
    Currently, the view helper StatusMessageFormatter reacts to the values of the constants so, if anybody would change the value of the class properties, he also should change the helper class that reacts to this. This is why I need to prevent people from changing it at runtime.

  4. Also, are you using the terms ‘Model Object’ and ‘Value Object’ interchangeably? Are they the same thing or different?

  5. I have just started in on Cairngorm and have found your articles very helpful. So far all that I have learned from you has just made me like the program more and more. I would like to continue learning more about it so I can continue to grow in my understanding and usage of it. Are there any more sites that give information on it? I have been looking around and have yet to find any have been as informative as yours have been. I do look forward to more of your articles on this and other subjects. Have you any on the new JavaScript standardization that is currently underway? I have heard a lot of talk about it, but no real facts about it. So if you have any information on this, I would very much like to read it. Thanks in advance

  6. tpde says:

    nice Articles!

  7. I’m still a newbie on Cairngorm and I think I still have lots of things to learn. Do you have any online tutorial for people who are beginners on Cairngorm?

  8. Ivan says:

    Good article.

  9. Flvay says:

    First of all, thanks for your really helpful blog!
    But i have one question:
    In your StockPurchase-Class you have a reference on StockQuote. But you don`t validate the isValid-Propery if the lastStockQuote-Property of the stockQuote changed.
    Image the follow:
    I type in my Quantity,after that I click to get the stockQuote. The result is that the isValid-Propery in the StockPurchase-Object is still false,because there is no validation if the stockQuote.lastStockQuote has changed.
    Do you have an idea to fix that.
    I have that Problem in my Project,where I have a Login-UseCase-Object.My other UseCase-Objects have to react on the changes in the Login-UseCase-Object.
    Thanks, Flavy!

  10. AlexU says:

    Hi Flavy,
    I don’t have the code in my head at the moment, but I would think you should be able to have the StockQuote object dispatching an event that is handled by its parent StockPurchase every time the StockQuote object updates. I’d probably define a custom event and also unit test this using FlexUnit EventfulTestCase.

  11. Flvay says:

    Thank Alex,
    it is really good that a model-object(StokeQuote) dispatches events. I afraid that it isn’t a good design?
    Greets Flavy

  12. AlexU says:

    What do you see wrong with that design? StockQuote is a child of StockPurchase and doesn’t have a direct reference to StockPurchase, only an indirect one (Observer relationship). That’s quite a usual thing to do. Make sure you test these connections though. Alternatively, you could update StockPurchase with passing its reference into the child and hide the StockPurchase API via an interface that just exposes the update interaction.

  13. Flavy says:

    If you think that is a usual approach, I believe in that. Thanks for your help! And as I said before,you doing a really good job here 😉