Wednesday 4 March 2009

Getting Started with OpenFlux 1: the basics

In this example I’ll show you how to create a useful component for social networking websites: a Link to a user’s page with the user’s photo, name or both. Then in part 2 I’ll show you how to organize them into a list and connect them with Cairngorm. The OpenFlux framework is somewhat different to vanilla Flex - forget everything you already know for now - later things will start to reconnect.

These tutorials requires active participation, try writing the code as you read the samples. I recommend you type everything in as FlexBuilder will autocomplete a lot of imports and assign namespaces. Even if you just cut and paste a bit, it’s good practice to make the individual file. The really fascinating thing about OpenFlux is seeing how all the different classes work together - the architecture. After the next release of OpenFlux I’ll post a video version too.

These are 'my' methods of using OpenFlux not 'the' method and certainly not the only one. In particular it is common to use public variables on Component, rather than a VO, as the data model. I prefer this approach as it works smoothly with Cairngorm, as we shall see in part 2... but I'm getting ahead of myself.

The first step is to identify how the component will be used in an application, it’s ’use cases’. There are two kinds of use case for a visual component. They display dynamic information and respond to certain user gestures (i.e. mouse or keyboard events). So we ask ourselves:

  1. what does it show?
  2. what does it do?

Then we write a Value Object (VO) that provides the information necessary for the component to do and show what it will. A VO is simply an actionscript class that has only public properties or getter/setters. A VO will act as Data Model for our component. Link shows a photo and the user’s name. Therefore our component’s VO requires a string for the name and another string for the URL where the image will be found:

public var photoUrl:String;
public var name:String;

We want to show the user’s page when the Link is clicked, so the component also needs to know the user’s ID:

public var userID:uint;

So we create a class called LinkVO that has nothing but these 3 public variables. Eventually this class will hold information received from our server, mapped with remote class metadata to a java equivalent.


Next we need to make a few more files. First the component itself, Link, which holds all the other parts together. Then we will make a two views; one with the user’s name the other with their photo. Being able to readily change the apparence of components is a major strength of OpenFlux, and is far easier to use than messing around with Flex borderSkin assignments etc. etc. Finally we’ll  write a simple controller that will subscribe responses to mouse clicks on the view.


role name extends
componentLink.as ListItem
viewTextLinkView.mxmlFluxView
viewImageLinkView.mxmlFluxView
controllerLinkController.asFluxController

The view is displays information. The controller responds to user gestures. The component stores the VO and sets the default view and controller. I recommend the pictured folder structure. In the downloadable files these are at.newbe.model etc. 

Link - component

First override the getter and setter functions for data from the parent class (ListItem). I’ll talk more about data when we put our Link in List. We’ll runtime type check that a LinkVO has been assigned to this property:

private var _linkVO:LinkVO;

override public function get data():Object { return _linkVO; }

override public function set data(value:Object):void {
if (value is LinkVO) _linkVO = value as LinkVO;
}

ListItem implements IFactory with its newInstance():* method. We must override this so it returns a Link, rather than a ListItem. Implementing IFactory allows a component be a List’s item renderer.

override public function newInstance():* {
var instance:Link = new Link();
return instance;
}

Finally we’ll set the default view and controller. We do this by overriding the protected createChildren() method. If the view or controller are undefined, set values as new instances of the defaults. Mark the class as [Bindable] And that’s it! Check the class you have written is the same as the downloaded file.

override protected function createChildren():void {
if(!controller) controller = new LinkController();
if(!view) view = new TextLinkView();
super.createChildren();
}

TextLinkView - view showing user’s name

Now we’ll make a very simple view that will display the user’s name. Open tags for the property +content, within them place a label with text bound to {component.data.name}:

<flux:content>
<mx:Label text="{component.data.name}"/>
</flux:content>

All visual components that will be displayed by the view are placed within the FluxView’s content variable. Anything else, like degrafa fills/strokes and states go outside. Note that you can access the component with the eponymous variable, and thus we bind the view directly to the VO. I love <10 line classes!

PhotoLinkView - view showing user’s profile photo

Next a more interesting view that shows the user’s profile photo. There are lots of ways to do this, but this is by far the best I have found. We’ll display the photo using a Degrapha image fill, with an image loaded from the photoUrl property of LinkVO:

<paint:BitmapFill id="photo" source="{component.data.photoUrl}" smooth="true" repeatX="{BitmapFill.STRETCH}" repeatY="{BitmapFill.STRETCH}" />

One advantage of this method over the default Flex Image component is advanced anti-aliasing, set by smooth="true". This fill will scale to the size of the shape it’s applied to. Next we’ll make a solid-stroke outline for the photo, and a rectangle for fill
and stroke to be applied to:

<degrafa:SolidStroke id="edge" color="#FF9900" weight="2" caps="round" joints="round" pixelHinting="true" />

<degrafa:GeometryComposition graphicsTarget="{[image]}">

<degrafa:RoundedRectangle width="{width}" height="{height}" fill="{photo}" stroke="{edge}" cornerRadius="2.5" />

</degrafa:GeometryComposition>

The graphicsTarget is a component called image within content. This will simply be another FluxView. Think of FluxView used this way as similar to how you might use Canvas in Flex Component development:

<flux:content><flux:FluxView id="image" width="{width ? width : 54}" height="{height ? height : 54}" /></flux:content>

The number 54 in the width and height setting are the default width and height setting for this component. I’ve tried several other ways of setting defult height, including measure() and setting in the parent tag of the mxml document. It seems that currently there are bugs if you have only degrafa shapes within content. This seems a neat enough solution, thoughts on performance anyone?

LinkController - controller

This  controller is very simple, in part because of some of OpenFlux’s fantastic custom metadata tags. Create a private variable with the same and type as our component, Link. Now add the [ModelAlias] tag before it, and this variable will represent a typed reference to the component at runtime.

[ModelAlias] private var link:Link;

This can save a lot of runtime type checking in more sophisticated controller. Now add the following metadata at the top of the class:

[ViewHandler(event="mouseUp", handler="mouseUpHandler")]

public class LinkController extends FluxController

The ViewHandler tag helps you listen to mouse and keyboard events from the view, and name a handler to respond to them. In this case we’re listening for mouseup with a handler called mouseUpHandler. Let’s define that function:

metadata function mouseUpHandler(event:MouseEvent):void {

trace( "please show me the user’s page" );

}

Note that we define a metadata function, rather than private. This allows the metadata processor to wire things together properly. Next episode we’ll dispatch a Cairngorm Event call from this function... bet you can’t wait! Using the metadata is crucial to getting the most out of OpenFlux, this is a taste but much more is possible. I explain fully how to use these and the other metadata tags in this blog post.

Testing our new component

Open up Main.mxml and create a LinkVO with some dummy information. Then make a PhotoLinkView. Then create a 2 Links in an HBox, and bind it’s data property to the LinkVO:

<vo:LinkVO id="user1" photoUrl="assets/images/01.jpg" name="Flexy Frederick" userID="1" />

<views:PhotoLinkView id="photo" visible="false" />
Then create a 2 Links in a VBox, and bind their data properties to the LinkVO. Set the PhotoLinkView as the view for one of them:
<mx:VBox>
<view:Link data="{user1}" view="{photo}" />
<view:Link data="{user1}" />
</mx:VBox>
Compile as see the user’s photo followed by their name. Click on either of them and the controller will trace. Congratulations you have now mastered the basics architecture of a single OpenFlux component. In part two we’ll use Link as an itemRenderer for the List component, an advanced container supporting dynamic layouts. We’ll also hook things up to Cairngorm, a powerful Adobe supported MVC application archetitecure.