Swiz Autowire View

Swiz got a new feature which allows you to autowire views into any class which has been loaded in a BeanLoader. A target could be a controller class which wants to interact with a view. Normally you would say that the view dispatches events which are then handled by a controller to decouple them but there are scenarios where you wish you had access to the view directly to avoid a large Script tag in the view component.

Disclaimer
Swiz does not require or encourage code behind, just that we decided to support this rare use case for the sake of flexibility.

In this first version Autowire view works only for accessors what should be the common usecase meaning you can autowire a setter with the [Autowire(view=true)] metadata above the setter:

[Autowire(view="true")]
public function set myView(view:MyView):void
{
	//...
}

The setter is invoked when the view is added to the stage and has dispatched the creationComplete event meaning all elements in the view are created and can be accessed. Since all MXML members are public this gives you quite some power but use it wisely to not introduce unnecessary coupling. Because a view is not a bean you have no bean attribute in the Autowire metadata but you autowire by type.

Example handling NativeDragEvent in an AIR app:

This code to handle drag-n-drop usually ends up in the Script block because you have to add the event listeners for dragEnter and dragDrop on for instance a Canvas. One could of course dispatch this further with custom events to a controller which could do the logic but I think letting a class directly add the event listeners could save this extra code:

package example.ctrl
{
	import example.model.SomeModel;
	import example.view.DragView;
 
	import flash.desktop.ClipboardFormats;
	import flash.events.NativeDragEvent;
	import flash.filesystem.File;
 
	import mx.core.IUIComponent;
	import mx.managers.DragManager;
 
	public class DragController
	{
 
		[Autowire]
		public var someModel:SomeModel;
 
		[Autowire(view="true")]
		public function set dragView(view:DragView):void
		{
			if(!view.hasEventListener(NativeDragEvent.NATIVE_DRAG_ENTER))
				view.addEventListener(NativeDragEvent.NATIVE_DRAG_ENTER, dragEnterHandler, false, 0, true);
			if(!view.hasEventListener(NativeDragEvent.NATIVE_DRAG_DROP))
				view.addEventListener(NativeDragEvent.NATIVE_DRAG_DROP, dragDropHandler, false, 0, true);
		}
 
		public function DragController()
		{
		}
 
		protected function getFilesFromDragEvent(e:NativeDragEvent):Array
		{
			if(e.clipboard.hasFormat(ClipboardFormats.FILE_LIST_FORMAT))
			{
				var files:Array = e.clipboard.getData(ClipboardFormats.FILE_LIST_FORMAT) as Array;
				return files;
			}
			return null;
		}
 
		protected function dragEnterHandler(e:NativeDragEvent):void
		{
			var files:Array = getFilesFromDragEvent(e);
			if(files != null && files.length == 1)
			{
				DragManager.acceptDragDrop(e.currentTarget as IUIComponent);
			}
		}
 
		protected function dragDropHandler(e:NativeDragEvent):void
		{
			var files:Array = getFilesFromDragEvent(e);
			if(files != null && files.length == 1)
			{
				var f:File = files[0] as File;
				// notify your model that a file is dragged on the view
				someModel.addFile(f);
			}
		}
 
	}
}

Autowire view can give you more flexibility but for sure more responsibility so take care! So ask yourself twice if you are using the right approach when introducing Autowire view. However, if you have interesting scenarios where you can apply a decent pattern with this approach please share it.

Important

  • In some scenarios I have seen that the setter is called twice so you maybe want to add an initView flag. Have to figure out if this is caused by the way Flex works or if this is a Swiz bug.
  • Be always sure to add event listeners with a weak reference to enable garbage collection when the view is removed
  • When you store a reference of the view be sure to release it when the view is removed to enable garbage collection
  • Autowire view is considered to be used for custom components and I have not tried what happens when you autowire a Canvas or a Button or whatever 😉

13 comments to Swiz Autowire View

  • Hi Sönke,

    I’ve got 2 comments. First is, what you call a rare use case is in fact very common in the MVP pattern. Direct reference from View to its Presenter (which you call Controller) is preferred by many so it’s good to see this feature coming in Swiz.

    I’ve got one problem with it though which is my second comment. You typically do not want to reference a concrete View from your Presenter – you will probably want to reference an ISomeView interface and supply the concrete type only at runtime. Can I do it with Swiz 0.0.6?

    Ideally, Swiz should introspect what interface the concrete View implements and do the wiring correctly. Don’t worry whether an interface has more implementations or just a single one, every time you encounter creationComplete event, just find out which interface the component implements and inject it to the right beans. Does it sound reasonable?

    Thanks,
    Borek

  • Hi Borek,
    it might be a common MVP scenario to have interaction between the view and presenter but we don’t want to encourage code behind in any way.
    Currently you can’t autowire a view by its interface type. This can be added but in this first draft we want to keep it simple and avoid any overhead. I would appreciate if you would have a concrete example project.

  • JB Tellez

    Hi Sönke (and Borek,)

    We also use MVP pattern at my workplace but we are usually able get by with just autowiring the presenter to the view. So far this style has worked great with Swiz.

    But my question, simply out of curiosity, is “Why don’t you want to encourage code behind in any way?”

    I have a few reasons I prefer to not use code behind, though several very good AS3 developers love it. It seems that you don’t care much for “code behind” Sönke, and I was just wondering why.

    Thanks for all your work on this awesome project,

    jb

  • Hi JB,
    I think it really depends on the style you want to code and if you like code behind you are free to use it this way. However, we don’t want Swiz to be understood as code behind technology. I think the beauty of Swiz is the flexibility which enables developers to code how they want and how it fits best to solve a given problem.
    What do you think about the example I made with “decoupling” the drag handler from the view?

  • Hi Sönke,

    I will post into the Swiz Google Group with a sample project when I have time. Basically, what I would love to see is support for this:

    [Autowire(view=”true”)]
    public var myView : IMyView;

    Swiz currently supports only concrete type like MyView which makes the Presenter tightly coupled to the View which is not good practice and it also makes testing of such presenter hard.

    Cheers,
    Borek

  • him_aeng

    I think this is the solution of my scenario. I use Flash CS3 .swc file that publish from Flex Component Kit.

    When I use this flash view I have to add many line of “addEventListener” and check for the frame was entered or not? (if the frame was not entered, its child component was not instantiate).

    So, with swiz ViewPackage I can separate the “addEventListener” code to another file even though it promote tightly coupling pattern but for flash component view I think swiz viewPackage is nice solution.

    awesome guy.

  • @Sönke,wow. I’ll try to use it right now and let you know the result.

  • Matt Ganski

    This is great. I understand its not an MVC best practice to do this in controllers. However, in my project, I have classes that are non views, yet they can ask the controller to make service calls. Since the class is a non view class, it must be declared as a bean in order for me to mediate events. I found myself using a public property setter to set a reference to a view in my application. Now with this, no setter necessary, I can inject the view I want right in when it’s created. Thanks!

  • Rupert

    Hi I wonder if it’s possible to wire two different view instances to two different view mediators.
    I mean:
    mediator1—–>employeesPanel(Panel)
    mediator2—–>productsPanel(Panel)

    where mediator1 and 2 are instances of different mediator classes and employeesPanel and productsPanel are instances of Panel.
    Is it posible to specify an id on the autowire tag?
    Hope I have expressed myself correctly.

  • Rupert, currently Swiz only support autowire view by type so you would have to subclass Panel to inject them by type into different mediators.

  • Rupert

    Ok, thanks a lot Sönke. I am taking my first steps with Swiz and I find it very interesting, ligthyears ahead from Cairngorm2 (which I used a few times). I wonder if there is some documentation available about all this Swiz tags features. I have already browsed swizframework.org and read the examples but I think they not cover all the nice features Swiz offers. I don’t want to sound ungrateful like demanding more documentation I see swiz team efford and goodwill, just asking if you could recommend some posts, lectures, books or whatever.

    best regards.

  • I am glad that you like Swiz and yes, it feels so good when you come from Cairngorm and can get rid of all this boiler plate code!
    swizframework.org should have all main docs. For further information try the blogs of the Swiz team members and examples listed on swizframework.org.

    Swiz 1.0 is around the corner so be sure to get tons of new docs and examples soon.
    However, this should not stop you from using 0.6.4 and when 1.0 is ready the transition should be pretty easy.

  • Rupert

    Great Sönke I will keep an eye on swiz site for 1.0 release.
    best wishes and good luck!