Vous êtes sur la page 1sur 4

= Working with Swiz Controllers = You may have noticed that our UserController extends AbstractController.

AbstractController is provided by Swiz and gives you a few convenience methods for dealing with Async requests. These are convenience methods for using DynamicResponders and DynamicCommands. These objects are quite similar, but DynamicCommand can be added to a CommandChain object, which is useful for running a series of tasks a the same time before proceeding to a final task. Let's take a look at how we can use each of these. We'll start with a DynamicResponder, and use a simple HelloController to illustrate its use. public class HelloController extends AbstractController { [Autowire(bean="helloDelegate")] public var helloDelegate : HelloDelegate; [Bindable] public var message : String; public function HelloController() { } public function sayHello() : void { executeServiceCall(helloDelegate.sayHello(), hello_results); } private function hello_results( result : ResultEvent ) : void { message = result.result.toString(); }

HelloController first declared a dependency for a HelloDelegate, which has been autowired with a RemoteObject to communicate with a HelloService end point on the back end. I could have simply wired in the helloService RemoteObject directly as well. In HelloController's sayHello() method, you see the use of AbstractController's executeServiceCall(). By passing in the call to helloDelegate.sayHello() as an argument, we are actually providing the AsyncToken returned call. This would be the same as directly calling the method on the RemoteObject. We also provide the result handler we would like to be called when the AsyncToken returns a result. Optionally I could have also passed a fault handler as well as an object I would like to have returned with the result event. Behind the scenes, Swiz will create a DynamicCommand object for, which implements Flex's IResponder interface. The result handler function we passed in will be invoked in the DynamicResponder's result() method, or if a fault occurs, either Swiz's default fault event (which displays an alert) or the fault handler you provided will be invoked. In the case of a successful result, if we had provided a object as the fourth parameter, it will be available to your result handler. This is particularly useful if you were to create say a new User object, and call save. When your service returns the newly created User, you may want to simply update the id on the original object you saved. Because Swiz was encapsulates dealing with the state of the AsyncToken for you, the traditional approach to writing boiler plate Command objects is completely removed. This approach leads to cleaner and easier to follow logic in your controllers. As you can see in the code above, I have taken the result of the sayHello() call and stored it locally in the variable 'message', instead of passing it on to a ModelLocator, underscoring Swiz's approach towards encapsulation. Let's see how you would use this HelloController in a view. First off, I need an instance of HelloController in my View. Again, we'll will use

Swiz's Autowiring capabilities by adding a public variable with the Autowire annotation, such as the following: [Bindable] [Autowire(bean="helloController")] public var helloController : HelloController; Now we attach the hello controller's sayHello() function to a button, and the bindable 'message' variable to a text field. <mx:TextArea text="{helloController.hello}"/> <mx:Button label="Say Hello!" click="helloControler.sayHello()"/> That's all there is to it. All the necessary logic for dealing with the RemoteObject is abstracted from your View by a simple controller. Swiz handles autowiring the components together, and provides some useful utilities to enable simple handling of the asynchronous remote service calls. Pretty cool! Now that we've covered DynamicResponders, lets see what we can do with DynamicControllers and Command Chains. Sometimes simply making one remote call and moving on will not work for your business logic. Perhaps on application startup you need to load a few different sets data (for instance data for combo boxes or localized text strings) before displaying your main application views. CommandChains allow you to create a series of DynamicCommands, with AbstractController's createCommand() method, and add each to a CommandChain object. You then register a method to run or event to be broadcasted when the commands in the chain complete. After registering your commands and complete handler you call execute() on the chain. When you create the CommandChain, you can choose if the Commands should run in series or parallel. Let's see what this looks like in practice. We'll use the HelloController from the previous example, but before diving into creating the command chain, lets take a quick look at the HelloDelegate that we autowired into HelloController. public class HelloDelegate extends AbstractDelegate { [Autowire(bean="helloService")] public var helloService : RemoteObject; public function HelloDelegate() { } public function sayHello() : AsyncToken { return helloService.sayHello() } public function echo(message : String) : AsyncToken { return helloService.echo(message); } public function showTime() : AsyncToken { return helloService.showTime(); }

The helloService RemoteObject is autowired into the delegate class, which contains methods that have the same signatures as our remote service methods. Each function simply returns the AsyncToken created when invoking the remote call. When we create our DynamicCommands, we will pass in pointers to the functions in this class, instead of directly calling them. This allows the DynamicCommant to delay the remote method invocation. Now

let's take a look at our HelloController. We'll add a runAll() method that uses a CommandChain to invoke all three methods from the HelloDelegate at once, and then calls a function internal to the controller when the chain completes, all three remote method calls have returned results. public class HelloController extends AbstractController { [Autowire(bean="helloDelegate")] public var helloDelegate : HelloDelegate; // a few bindable [Bindable] public [Bindable] public [Bindable] public message results var helloMessage : String; var echoMessage : String; var timeMessage : String;

public function HelloController() { } public function runAll() : void { // first set the messages to running helloMessage = "running..."; echoMessage = "running..."; timeMessage = "running..."; // create a new CommandChain object var chain : CommandChain = new CommandChain(CommandChain.PARALLEL); // use AbstractController's createCommand function to build a DynamicCommand object for each // delegate call and add each to the command chain chain.addCommand(createCommand(helloDelegate.echo, ["swiz rulz!"], echo_results, local_Fault)) .addCommand(createCommand(helloDelegate.showTime, null, time_results, local_Fault)) .addCommand(createCommand(helloDelegate.sayHello, null, hello_results, local_Fault)); // now set a complete handler and call proceed to execute all the commands chain.completeHandler = completeHandler; chain.proceed(); } private function hello_results( result : ResultEvent ) : void { // set the hello message to the result string helloMessage = result.result.toString(); } private function echo_results( result : ResultEvent ) : void { // set the echo message to the result string echoMessage = result.result.toString(); } private function time_results( result : ResultEvent ) : void { // set the time message to the result string timeMessage = result.result.toString(); } private function completeHandler() : void {

// to run my complete handler, let's show how to broadcast an event through Swiz Swiz.dispatch("chainCompleteEvent"); } private function local_Fault( info : Object ) : void { trace( "\n\nFault retrieving data..." ); trace( ObjectUtil.toString( info ) ); }

We see a very similar set up as before with the DynamiResponders, with local result handers and bindable variables to store the result of each call. However, instead of using executeServiceCall(), we are using createCommand to build DynamicCommands. The first parameter to createCommand is not the AsyncToken we would get by directly calling the delegate methods, but a pointer to the Function object itself. The second parameter is an array of arguments that DynamicCommand will be passed into that Function at run time. The last two arguments are the result handler for each call, and a local fault handler to override the Swiz's default fault handler. In this example we are passing an array with a single string to the helloDelegate's echo function, which will evaluate to helloDelegate.echo("swiz rulz!") in the DynamicCommand's execute method. Take particular notice that we have passed null into the other delegate methods, which accept no arguments. After creating the CommandChain we add each of the DynamicCommands created with createCommand(), then assign a completeHandler, which is a local method. Now that the Chain is contructed, we can call proceed(). Since we used CommandChain.PARALLEL in the Chain's constructor, all three methods will execute at the same time, and after they all complete, the final completeHandler will be called. If we had passed in CommandChain.SERIES as a constructor argument, the chain would only call execute() on the first command in the chain. When the result is returned to the command, the chain would then fire the second command, and so on until they have all completed, at which time our chainComplete Function will be called. If there is a failure in any DynamicCommand, it's associated fault handler (in this case local_Fault) will be executed. You can further add a faultHandler to the chain itself. The effect of a failed remote call varies based on the mode we set the chain to when we created it. Since all commands are fired at the same time with a PARALLEL type Chain, all DynamicCommands will execute to completion regardless of any fault, however a SERIES chain will immediately call the fault handler and exit if a fault occurs, with no further commands executing. Finally, we can use completeEvent and faultEvent instead of passing in Functions, and Swiz will broadcast either event as necessary. This enables quite a bit of flexibility in development style. To use the CommandChain we built, we simply execute the HelloControler's runAll() method, just as we did sayHello() in the previous example, and bind a few text elements in a view to the HelloControler's echoMessage, helloMessage and timeMessage variables. You may have noticed the dispatch call on the local completeHandler. This uses another feature of Swiz, it's CentralDispatcher.

Vous aimerez peut-être aussi