This page describes the container classes in FlexJS. A “container” is a UI component that has one more children organized using a layout. You would use a container to group together other UI components to size and position them in relation to each other. The children of a container may themselves be containers.

FlexJS has several container classes: View, Group, Container, DataContainer, List, and charts. The View, Group, and Container classes can have their children defined in MXML or added via ActionScript. DataContainer, List, and the charts have their children added algorithmically using a data source.

The class inheritance diagram (Figure 1) shows how the classes are related. In the FlexJS fashion, there are corresponding view beads. The view beads are managing the actual on-screen aspects of the component.

FlexJS containers use layout beads to size and organize the children in a container. For example, the HorizontalLayout bead places each child, in order of their addition to the container, in a single row. If you later decide to place the children in a single column you would just change the bead to the VerticalLayout bead; nothing else has to change in your application.

Layout beads monitor the container for changes: additions, deletions, and changes to the size of the children. It is incumbent on each layout to respond to these events in whatever way is appropriate.

Layout beads are used with every container class. This means you can make a horizontal list or vertical list or lay out the contents of a list in rows and columns. You do not need to change the list or the data at all.

Figure 1: FlexJS Container Classes

Life Cycle

When a component/strand is added to the display list, the following sequence of events happen. Keep in mind that children of the container will also go through this same process.

  1. After attaching the component’s core (platform-specific) element to the display list, the FlexJS framework calls the component’s addedToParent() function.
  2. The addedToParent() function looks at the list of <js:beads>, if any, and adds them to its bead strand. This act trigger’s each bead’s strand setter function.
  3. Once all of the <js:beads> have been added, addedToParent() looks to see if a model bead is now on the strand. If it is not, the CSS style for the component is found and if a model bead class is specified, an instance of the model is created and added to the strand.
  4. The same is done for the view and controller beads.
  5. Finally, addedToParent() dispatches a “beadsAdded” event.

When “beadsAdded” has been sent, any listener can be assured that all of the <js:beads> have been added as well as the standard beads (model, view, controller) if the component has specified them.

Doing the bead sequence in this order allows beads to be placed in <js:beads> that will override the standard beads. For example, if you specify a different model bead, when addedToParent() gets to the step where it would add the default model bead from CSS, it will see that a model is already present and skip adding the default model bead.

The container classes, View, Group, and Container, override addedToParent() and do a few more steps:

  1. After calling super.addedToParent() - which will dispatch “beadsAdded” - the container components prepare for the addition of MXML children that may be specified inline.
  2. This causes those children to be added to the display list (the sequence above is then repeated for each of those children). When all of the MXML children have been added a “childrenAdded” event is dispatched.
  3. Finally, “initComplete” is dispatched.

The list-based containers, DataContainer, List, and the charts, follow a slightly different path in their override to addedToParent():

  1. After calling super.addedToParent() - which will dispatch “beadsAdded” - the container components attempt to load their data mapping and item renderer factory beads.
  2. In the same way the standard beads are added, the beads list is first examined to see if the beads are already present (you may want to change the data mapping bead, for example). If not, the container’s CSS style is examined for a default class. An instance is created and added to the strand.

Content Area

The content area of a component is the location within the component’s bounding rectangle that houses (or will house) the component’s children. Because FlexJS is multi-platform, consideration is given to each platform and how to adapt to that platform’s abilities.

In an earlier version of FlexJS, all container classes were composed of the container’s display space and an inner object (the ContainerContentArea class and its derivations). When this structure was cross-compiled from ActionScript into JavaScript and run in a browser, it resulted in a DIV-within-DIV structure that was often unnecessary and proved to be hard to style.

The nesting of these parts was created to accommodate the Flash Player and used as a way to mimic the abilities of the browser and HTML DOM: scrolling and clipping. The current version of FlexJS does away with the nesting structure for the HTML platform and uses it with more care on the Flash platform.

The Group container class provides the simplest form of containment. On the HTML platform it translates to a single DIV and is its own content area. On the Flash platform, the Group container translates to a DisplayObjectContainer and is also its own content area.

The Container container class also translates to a single DIV on the HTML platform. On the Flash Platform however, the Container is a nesting of display containers and it is the inner object, an instance of ContainerContentArea, that is the Container class’s content area. This is done to mimic what the DIV can do in the browser: provide clipping and scrolling which are not naturally occurring in the Flash Player.

Most classes derived from Container have this platform duality. The exception are the chart classes which use a separate inner container for the chart graphics (ChartDataGroup) on both platforms to separate that area from the areas used for the axes.

Unless you need scrolling and clipping, it is recommended you derive your own components from Group (when you want to have MXML children and layout) or GroupBase (when you just need layout).

Beads

When a bead is added to the strand, its strand-setter function is called:

function set strand(value:IStrand):void;

A bead should use this opportunity to initialize values and set up event listeners on the strand for either “beadsAdded” or “initComplete”.

Keep in mind that “beadsAdded” is called after the <js:beads> and standard beads have been added - but more beads may be added after that. If the bead depends on the existence of other beads, then either wait for “initComplete” or a custom event to signal that the component is ready and that all beads are truly present.

At this time only container beads (and a few others) dispatch “initComplete”. It is recommended that if your custom component overrides addedToParent() and added more beads or does something that will affect how other beads behave, addedToParent() should dispatch a final event, such as “initComplete”.

Layouts

A layout bead performs the function of sizing and positioning the children of a component’s content area. A layout bead sets up listeners for changes to the component’s overall size and listens for changes to the size of its children as that could affect how the layout is performed.

Each layout bead provides its own layout algorithm. For example, the HorizontalLayout bead places each child of the content area end to end in a single row. The VerticalLayout bead places each child of the content area top to bottom in a single column. The algorithm used has full control over the space provided by the content area (and may even exceed it if necessary to fulfill the layout).

All layouts should derive from LayoutBase which provides common functions and serves to handle the events by calling on overridable protected functions which can be changed or used by custom layout subclasses. For example, LayoutBase provides a function to determine a child’s margins and the listen for the resizing events, triggering the layout algorithm. Subclasses mostly deal with the actual layout process.

Composited components, such as Panel and DataGrid, use layouts internally. For example, a Panel is derived from Group and uses the VerticalFlexLayout which positions and sizes its title and control bars and sizes the Panel’s content area to expand to fill the remaining space.

If you build a custom component and derive it from Group or GroupBase, you can use a layout (supplied with FlexJS or a custom one) to handle how and where the sub-elements appear.

Layout algorithms are usually platform-dependent. Mostly, the layouts are written for the Flash Platform to mimic what HTML does with a DIV and some CSS styles such as display and position. On the HTML platform, the layout code may even be nonexistent!

The typical layout algorithm for the Flash platform works like this:

  1. The content view is obtained from the host strand.
  2. The workable dimensions of the content area are calculated by subtracting the component’s padding and margin styles.
  3. The initial X and Y position of the layout children are offset by the top and left margin and padding.
  4. For each child, its size may be changed or determined if the child is being sized by percentage of the host. This is dependent on the type of layout algorithm: some layouts need to know what size the child is and some simply set the size of the child regardless of what the child may want to be.
  5. The child is positioned and the X and Y positions of the next child are calculated.

That was an oversimplification but the process generally follows that pattern.

The component’s view bead also plays a role in the layout process. Generally, the view bead implements ILayoutHost since it knows which of the visual children of a component is the content area. As part of the ILayoutHost protocol, view beads are required to implement a beforeLayout() function and an afterLayout() function. These functions are called by the layout bead to give the view bead an opportunity to prepare for layout and to deal with the result of the layout.

For example, if a component is not given an explicit or percentage size, then it is considered to be “sized by its content”. In order for the size to be determined, the layout has to be performed. Once the layout is performed, the view bead’s afterLayout() function can calculate the space the children now occupy and determine a bounding box which becomes the component’s official size.

Summary

Container classes in FlexJS attempt to give preference to the HTML platform and defer to that as much as possible by generating as simple a DOM structure as possible that represents the application.

Some classes, such as Container, are present mainly for the benefit of the Flash platform. You can easily add styles to a DIV (generated by the Group class) that will make it scroll, but if your application runs on all platforms, then you need to use Container in order to have scrolling on the Flash platform.

The layout beads provide the structure to the component by arranging and sizing its children. FlexJS lets to swap layout beads to change the look and feel of a component without having to change any other aspect of the component’s function.

  • No labels