Strands and Beads

Adding functionality to a component through composition

Strands and beads are key concepts in Apache Royale, related to the PAYG (pay as you go) concept. The idea is to keep component code as lightweight as possible, and to add functionality and complexity only to the components that need it.

Fig 1: MVC with Strands and Beads

In the image, a TextInput is composed by a model (TextModel), a view (TextInputWithBorderView) and a controller (EditableTextKeyboardController). These are the minimun MVC beads to make it work for this component.

For example, you may use a lot of text input fields in your application, but only one or two need to be able to protect passwords by converting the display of text the user provides into dots. You may want to disable or enable some instances of the text input component, but not all of them, while an end user is working with your application. There is no reason to have that extra functionality (and added weight of code) available everywhere “just in case”, as was the rule in Apache Flex.

Fig 1: Adding optional Beads to the Strand

In the image we are composing (adding) two optional beads to the strand.

Every Royale component contains the minimum code necessary to perform its basic functions, and has “strands” onto which you can string “beads” of functionality that let an instance of the component do what you want it to do in a particular place in your application.

Finding the beads you need

Finding the beads that will provide what you want for a given component, or even knowing what beads are available in the official Apache Royale SDK can be a daunting task. There are hundreds of these little pieces of code distributed all over the framework code. For this reason we are gradually assembling a list of beads on each component page, so users can refer to a concrete strand (the component) and see a list of beads that work with it. Normally you can have:

Adding a bead

There are three ways to add beads to a component: bake it into the code using <j:beads>, declare it through CSS, or add it dynamically using addBead().

Adding a bead directly in the code

Each strand supports a beads array and users can add beads in MXML.

In the following example we are using the Jewel TextInput strand to add Jewel TextPrompt and Jewel Disabled beads to the strand. Note that while TextPrompt is specific to TextInput, you can use Disabled with many Jewel components.

<j:TextInput text="Disabled with text...">
    <j:beads>
        <j:TextPrompt prompt="Disabled TextInput..."/>
        <j:Disabled/>
    </j:beads>
</j:TextInput>

Adding a bead through CSS

Adding beads through Cascading Style Sheets (CSS) is easy. You declare CSS rules where the selector is the strand and the declaration block has one or more delarations. Declarations can be bead declarations or standard CSS declarations separated by semicolons.

A bead declaration has the bead type as the property part (for instance, IBead, IBeadModel, and IBeadView) and a ClassReference to the bead we want to assign as the value part.

Here is an example of a CSS bead declaration. We assign org.apache.royale.jewel.beads.views.ListView as the bead view (IBeadView) of the component strand:

IBeadView: ClassReference("org.apache.royale.jewel.beads.views.ListView");

Royale uses CSS to configure components with defaults beads. The following code snippet is the default initial bead configuration for a Jewel List and is declared though SASS (that gets compiled to CSS).

j|List
    IBeadView:  ClassReference("org.apache.royale.jewel.beads.views.ListView")
    IBeadController: ClassReference("org.apache.royale.jewel.beads.controllers.ListSingleSelectionMouseController")
    IBeadLayout: ClassReference("org.apache.royale.jewel.beads.layouts.VerticalLayout")
    IItemRendererClassFactory: ClassReference("org.apache.royale.core.ItemRendererClassFactory")
    IItemRenderer: ClassReference("org.apache.royale.jewel.itemRenderers.ListItemRenderer")
    IViewport: ClassReference("org.apache.royale.jewel.supportClasses.scrollbar.ScrollingViewport")
    IViewportModel: ClassReference("org.apache.royale.html.beads.models.ViewportModel")
    IBeadModel: ClassReference("org.apache.royale.jewel.beads.models.ArrayListSelectionModel")
    IDataProviderItemRendererMapper: ClassReference("org.apache.royale.jewel.beads.itemRenderers.DataItemRendererFactoryForCollectionView")

Royale developers can override default beads through their own coded CSS files that will take priority over framework CSS rules, or through AS3 and/or MXML code.

Adding a bead dynamically with addBead()

The third way to add a bead is though ActionScript using the addBead() API method.

Here is example code:

// for the Jewel Alert component, retrieve the AlertView (IBeadView) 
var alertView:AlertView = alert.getBeadByType(IBeadView) as AlertView;

// create a VerticalLayout (IBeadLayout)
var verticalLayout:VerticalLayout = new VerticalLayout();
verticalLayout.gap = 9;

// add the bead layout to the content part of the view layout
alertView.content.addBead(verticalLayout);

See a full example of the code above in the Customization through the Royale API example.

Accessing a bead from a strand

There are many cases where you need to find a specific bead without necessarily knowing the implementation. The two most common cases are accessing a strand’s view and model.

For these two cases, any class which implements IStrandWithModelAndView or inherits from UIBase (which is pretty much every visual component) has direct access to the view and model getters on the strand. These getters should always be used for views and models.

Sometimes, a component might have more than one model and you might not be sure if the one you want is the main one. In that case you should use the getModelByType(strand,classOrInterface) function in the org.apache.royale.html.util package. It will find the correct bead in the most efficient way it can.

For other bead types, you can use strand.getBeadByType(classOrInterface). It will find the bead you need from the beads which belong to the strand. You can use this for views although it’s less efficient than accessing the view directly. You should not use this for models because models are only loaded the first time they are accessed and if you use strand.getBeadByType(IBeadModel) you will get null if the model has not yet been accessed.

Creating a bead

The following piece of code shows the most basic bead structure to use when you create a bead:

package beads
{	
	import org.apache.royale.core.IBead;
	import org.apache.royale.core.IStrand;
	import org.apache.royale.core.UIBase;
	
	/**
	 *  sample code for a bead class
	 */
	public class SomeBead implements IBead
	{
		protected var _strand:IStrand;
		
		/**
		 *  @copy org.apache.royale.core.IBead#strand
		 *  
		 *  @royaleignorecoercion org.apache.royale.core.UIBase;
		 */
		public function set strand(value:IStrand):void
		{
			_strand = value;

			// do something
		}
	}
}

All beads implement the IBead interface (or a subclass like IBeadModel or IBeadView) and can refer to the strand component using the strand method implementation of the IBead interface.

Beads can be tiny pieces of code so in this way we get great encapsulation of functionality with a few lines of code.

If you see the need for a bead that does not yet exist, you can create your own and contribute it to the Royale project. Information on the bead lifecycle is available at Creating Components.

Strand management

This section will include information on adding and removing beads and the significance of bead order