« Flex 2 Beta 2 | Main | A List itemRenderer using States and Transitions »

March 27, 2006

Component "Templates" in Flex 2.0

First, let me be very clear: Flex 2.0 does NOT support templates. But this article will show you a way to make it look and act as if it does.

A "template" is different from a custom component. A template typically specifies a number of parts with some of the areas left open for substitution. I think of templates as being done exclusively in MXML whereas components can be 100% ActionScript or a combination of AS and MXML. Dreamweaver has the ability to do templates using regions.

Note: An example is available for download at the end of the article.

Panel Template

Suppose you want to create a Panel with a certain look and use it frequently in your application. Perhaps the Panel has a ControlBar with a "Search" and "Help" button. You want to make sure the Panel has the ControlBar and Buttons all of the time, but you want to change the contents of the Panel. A template, called SearchPanel.mxml, to do this might look like:


<mx:Panel xmlns:mx="...." layout="absolute">
<mx:Metadata>
[Event("search")]
[Event("help")]
</mx:Metedata>
<!-- put children here -->
<mx:ControlBar>
<mx:Button label="Search" click="dispatchEvent(new Event('search'))" />
<mx:Button label="Help" click="dispatchEvent(new Event('help'))" />
</mx:ControlBar>
</mx:Panel>

To use this you might do:


<SearchPanel title="Employee Search" search="findEmployees()">
<mx:Form left="10" top="10" right="10" bottom="10">
... form items here ...
</mx:Form>
</SearchPanel>

If you were to write this in Flex today, you would get a compilation error saying that SearchPanel already had children. You cannot add more children from outside of the component. If you had written SearchPanel without the ControlBar, then this would work. But then every SearchPanel would not automatically have a ControlBar.

One solution is to write this as a custom component which creates the ControlBar and Buttons in ActionScript. I won't do that here because I have a much better way to do it.

Making the 'Template'

Let's go back to SearchPanel and keep it the same, except add in this Script block:


<mx:Script>
<[[CDATA
private var _components:Array;
public function set subComponents( a:Array ) : void
{
_components = a;
}
private function addComponents() : void
removeAllChildren();
for(var i:int=0; i < _components.length; i++) {
addChild( _components[i] );
}
}
]]>
</mx:Script>

and modify the root tag: <mx:Panel xmlns:mx="...." layout="absolute" creationComplete="addComponents()">

Now use this in your program:


<SearchPanel title="Employee Search" search="findEmployees()">
<subComponents>
<mx:Form left="10" top="10" right="10" bottom="10">
... form items here
</mx:Form>
</subComponents>
</SearchPanel>

Notice that the Form, and any other children you want to add to the Panel, are defined by the <subComponent> property. In the Script block for the SearchPanel, subComponents is a set method which takes an Array. This Array will be 1 or more components defined in MXML. In this example, that Array is the <mx:Form>. Notice that the simple loop just takes each element of the Array and adds it to the Panel.

Now you have a "template"!

Default Property

But wait - there's more. This is the really cool part. Go back into SearchPanel.mxml and add the following line to the <mx:Metadata> right after [Event("help")]:


[DefaultProperty("subComponents")]

Now change the main program just slightly by removing the <subComponents> tag:

<SearchPanel title="Employee Search" search="findEmployees()">
<mx:Form left="10" top="10" right="10" bottom="10">
... form items here
</mx:Form>
</SearchPanel>

Notice that <subComponents> is gone and this now looks like a real container. This works because of the DefaultProperty metadata. You've set the SearchPanel's default property name to be "subComponents" which automatically places the <mx:Form> into the subComponent array.

Conclusion

While real templates are not available in Flex 2.0 you can come mighty close to making it look as though they are. This is possible because of the way components are now created in Flex 2.0 (using the new operator) and the DefaultProperty metadata.

Download Example

This example is similar to the one described above. Here, the component is a Panel wrapped by a Canvas. This is done so that minimize and maximize buttons can float over the Panel's title bar.

Download file

Posted by pent at March 27, 2006 11:25 AM

Comments

I like this approach. Could you post a working example for us beginners to understand it better?
Thank you.

Posted by: lidija at March 27, 2006 02:02 PM

Great example Peter! I'll be sure to put it to good use. It's a great way to have custom components that already have child containers/controls.

Very neat!

-Andrew

Posted by: Andrew Spaulding at March 28, 2006 01:31 AM

I've added a zip file download to the end of the article. The zip contains a more complex example, but that is more realistic.

Posted by: Peter Ent at March 28, 2006 06:00 AM

Thanks a lot!

Posted by: lidija at March 29, 2006 10:46 PM

Great approach!!, is this coding way available in Flex 1.5?

Posted by: Javier at April 25, 2006 03:43 PM

Unfortunately this not possible in Flex 1.5. What makes this work is the ability to create components and then assign them to a container afterwards. Here, the presence of the component in MXML causes it to be created and then put into an Array and made available via the defaultProperty. Then the component (as an object) is added to a container.

In Flex 1.5, components could only be created by another component (createChild()).

Posted by: Peter Ent at April 25, 2006 07:59 PM

I wonder if above codings can be used with a ActionScript class so that there is only one generic SearchPanel that has following children:
1. form : capture the search parameters
2. datagrid : search results
3. control bar with few buttons - to serve user actions

With reasonably sized appliation there'd be various search screens. Whatever search module passes a parameter(search name, search object...) to the AS Class so that the class can dynamically create the SearchPanel with the children mentioned above, form, datagrid, controlbar.
Can Flex2 do this?

Posted by: Dong Lee at August 4, 2006 12:40 AM

You could do what you suggest with a properties for the different parts. For example:




...



...


If this is what you mean, I think Flex 2 can handle it.

Posted by: Peter Ent at August 4, 2006 07:16 AM

Thank you, this explanation makes more sense than the one in the documentation from Adobe.

I've found one drawback though. Using this approach you can no longer use the design view in Flex. It does not show the children in the MinMaxPanel. Is there a way around this?

If the alternative is to write the template in pure ActionScript, can you please give an example how this would work?

Thank you,

- Rob

Posted by: Rob at November 28, 2006 11:55 AM

Very elegant ... now suddenly most of these packaged components make sense to me. That metadata tag is very useful. Thanks!

Posted by: brent dearth at February 27, 2007 05:01 PM

Hi,

as Rob asked (Posted by: Rob at November 28, 2006 11:55 AM)
You cannot see the usage of templates and changes in design view of Flex. You see there only Template but no children in it, even if they are there.

Is there any possibility how to accomplish this?

Thanks a lot.
Tom

Posted by: Tom Krcha at April 23, 2007 10:01 AM

I'm afraid that still isn't possible with Flex 2. Perhaps it will be in a future version. You can always go to our wishform (http://www.adobe.com/go/wish) and make the request.

Posted by: Peter Ent at April 25, 2007 10:40 PM

Hi,

I'm preparing to have a web application developed in Flex 2.0 or 3.0 that allows someone to select a pre-defined HTML email template. The template would have frames for text and graphics, but the information inside are just placeholders. When the user selects a template they want to customize, it drops it into a drawing window. The user can now click on a frame inside the template to make it active and then drop-n-drop their graphic files. When they drop them into place, it would automatically fit them into the frame. They could also click on a text frame and begin typing or do a "paste". When they click on the text frames, the program will automatically open a rich text editor that enables them to adjust the font, size, etc. Ultimately, they could see how this looks using the WYSIWYG view and then save the file.

Does this sound like something you can do in Flex? If so, are you personally available to write this?

Thanks!
Chuck
-------------------
Peter:
Chuck, I'm not available to lend a hand here, but for something like this you should look at the Flex Rich Text Editor control (mx.controls.RichTextEditor).

The Flash player has limited support for HTML. Adding a true HTML renderering engine to the Flash Player would make it many megabytes in size and default the small footprint goal of the Player. So make sure RTE has what you need.

You can also look into Adobe AIR - this is essentially a desktop Flex app. But AIR does have a built-in HTML engine because AIR isn't expected to be downloaded on the fly. However, it too, uses the same RTE control.

Posted by: Chuck at July 23, 2007 11:17 AM

thanks, Peter. that's what I need.

Posted by: hans.xie at July 29, 2007 09:59 PM

Hi,

I tried writing another MXML component (newComponent) extended from MinMaxPanel, if I try to add any items to my newComponent I get the same error
"multiple sets of visual children have been specified". Is there a work around to this?

Thanks.
--------------------------
Peter: You have to follow the same pattern as the MinMaxPanel and add a property for your additional components. Since the MinMaxPanel is already using a default property, you'll have to make an explicit one.

Posted by: Muhammad Kamran Shafi at September 21, 2007 01:02 PM

thanks.

Posted by: ankara nakliyat at February 9, 2008 05:53 AM

thanks

Posted by: sohbet at April 4, 2008 12:38 AM

Thank you, this explanation makes more sense than the one in the documentation from Adobe.

Posted by: Ankara Evden Eve Nakliyat at April 17, 2008 07:37 AM

thanks, Peter. that's what I need.

Posted by: Ankara Evden Eve Nakliyat at April 17, 2008 02:58 PM

VERY cool stuff! Thanks a lot!

Posted by: Marcus Stade at April 20, 2008 03:57 PM

thank you

Posted by: ankara evden eve at June 25, 2008 04:34 AM

Very usefull!! Thanks a lot

Posted by: hemgui at June 26, 2008 05:39 AM

thank you

Posted by: evden eve nakliyat at August 8, 2008 04:55 AM

That's good workaround, but I'm not sure if the component inheritance is now available in Flex 3.0, because we are now building app using Flex 3, it seems if you directly inherits some custom component with UI objects, the errors still exist, thanks.

Posted by: Ramon at August 31, 2008 10:42 AM

Post a comment




Remember Me?