Adding a "ViewController" into your Cairngorm app
Posted by Joe Rinehart at 8:04 AM
11 comments - Categories:
Flex | Cairngorm
The other day, I posted about adding Cairngorm event listeners directly into your views. Just summarizing it like that, it should already sound like a wonky alternative to using ViewHelper/ViewLocator (which, to me, is even wonkier).
Here's my situation:
I have a login form that I'd like to have to something "special" when login fails, like blink or turn red or play a very loud siren noise. Whatever that is, I can't get there by just binding to a "workflow" value in the ModelLocator: I need to call a function in the view.
Jay Proulx posted a possible solution that created a separate "ViewController" concept, where a class would extend Canvas and define string constants representing various states. It's a nice way to separate the listeners out of the views, but it still doesn't go where I need to be: having functions that play things like effect sequences in response to architectural events.
So, I combined his idea, mine, and the basic UI event system to create my own ViewController class.
Here it is (nothing special):
{
import mx.core.UIComponent
import com.adobe.cairngorm.control.CairngormEventDispatcher;
public class ViewController extends UIComponent
{
private var dispatcher:CairngormEventDispatcher = CairngormEventDispatcher.getInstance();
protected function addListener(eventName:String, func:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void {
dispatcher.addEventListener(eventName, func, useCapture, priority, useWeakReference);
}
}
}
Nothing fancy. Extends UIComponent and adds an addListener() method that'll add a listener to the CairngormEventDispatcher.
However, I can then extend it with something like LoginViewController. LoginViewController adds a listener for the USER_LOGIN_RESULT_EVENT, and depending on the authentication status of the user involved, raises a plain old UI event:
{
import com.foo.control.ViewController;
import com.foo.control.user.AuthenticationController;
import com.foo.control.user.UserLoginResultEvent;
import com.foo.model.user.User;
import flash.events.Event;
[Event(name="loginFailed",type="flash.events.Event")]
[Event(name="loginSuccessful",type="flash.events.Event")]
public class LoginViewController extends ViewController
{
public function LoginViewController() {
addListener(AuthenticationController.USER_LOGIN_RESULT_EVENT, loginResult);
}
private function loginResult(result:UserLoginResultEvent):void {
var u:User = result.user;
var e:Event;
e = u.authenticated ? new Event("loginSuccessful") : new Event("loginFailed");
dispatchEvent(e);
}
}
}
Now I'm in business. Instead of dealing with views by an arbitrary ID (my main issue with ViewLocator/ViewHelper) or giving my view knowledge of the Controller view (my main issue with my earlier workaround), any view that wants to deal with login failures or login succeses can do this:
It's a bit like ViewHelper, but backwards enough where it works implicitly instead of explicitly.
John Allen wrote on 02/09/07 10:28 AM
AWSOME!!!! Im laughing that is so great! One of the best Flex tips ive seen!SOOOOO helpfull!
Keep this stuff coming!