Adobe Flex - Display a Visual Element from HostComponent in MXML - apache-flex

I have got a SkinnableComponent:
public class ContentView extends SkinnableComponent
{
[Bindable]
public var titleBar:IVisualElement;
public function ContentView(pContentXML:XML)
{
this.setStyle("skinClass", ContentViewSkin );
}
}
and now i want to display the titleBar in the mxml skin file.
<?xml version="1.0" encoding="utf-8"?>
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Metadata>
[HostComponent("EMM.App2Go.Viewer.Component.ContentView")]
</fx:Metadata>
<s:DataGroup width="100%" >
<s:dataProvider>
<s:ArrayList source="{hostComponent.titleBar}" />
</s:dataProvider>
</s:DataGroup>
as you can see I managed it with a DataGroup but this is kind of ugly, and I was thinking about an easier way to do this like
<fx:Object source="hostComponent.titleBar" />
or something like that.
I hope you can help me.

You seem to have a deep misunderstanding of how the Spark SKinning Model should work. You should not reference the hostComponent from the skin in order to display items. You should create the element in the skin; and use the same name. So if the hostComponent has a skin part defined like this:
[Bindable]
[SkinPart]
public var titleBar:IVisualElement;
the skin should have something like this:
<s:DataGroup width="100%" id="titleBar" >
</s:DataGroup>
I suggest reading through this information on Spark Skinning, and also learn the Component LifeCycle.

Related

Flex mxml custom component - how to add uicomponents?

how to I pass in a uicomponent to a mxml custom component?
ex: I want to pass in any number of buttons, and I want my custom component to lay them out in a certain order.
MainApp.mxml:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
minWidth="955" minHeight="600" xmlns:local="*"
>
<local:myComp >
<s:Button label='Button1' />
<s:Button label='Button2' />
<!--I want to add anything else here -->
</local:myComp>
myComp.mxml:
<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
creationComplete="init()"
width="400" height="300"
>
<fx:Script>
<![CDATA[
private function init():void {
// how do I access the added components and place them where I want?
// do I use removeChildren and AddChildren?
// addItemsHere.addchild(nextButton);
]]>
</fx:Script>
<s:HGroup id='addItemsHere' />
As your component extends Group, you shall use addElement instead of addChild (and for all other methods with 'child' in their name it shall be replaced with 'element'. So, access to all elements will be like that:
for(var i:int =0; i < numElements; i++){
var button:Button = Button(getElementAt(i));
doWhatIWantWithMyButton(button);
}
It is also better to override createChildren method of your component if you know what to add at the creation moment.
If you don't need very specific button placement, you can set layout property of your component to any desired layout (like VerticalLayout, for example), and those layouts are tunable.
You seem to be trying to recreate functionality that already exists in the SDK. This is wat SkinnableContainer is for.
Depending on your use case, there are two ways to use it:
You only need to add some custom graphic elements to you custom component, but no additional behaviour
In this scenario, you would simple reuse SkinnableContainer and assign it a custom skin, like so:
<s:SkinnableContainer skinClass="MySkin">
<s:Button label='Button1' />
<s:Button label='Button2' />
</s:SkinnableContainer>
With MySkin.mxml perhaps something like:
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Metadata>
[HostComponent("spark.components.SkinnableContainer")]
</fx:Metadata>
<s:states>
<s:State name="normal" />
<s:State name="disabled" />
</s:states>
<s:layout>
<s:VerticalLayout/>
</s:layout>
<s:Label text="I'm a SkinnableContainer"/>
<s:Group id="contentGroup" width="100%" height="100%">
</s:SkinnableContainer>
Your Buttons will now automatically be added to the contentGroup; the SkinnableContainer class handles this for you. Note that this Group must have exactly that id; it's a required SkinPart.
You want to add some behaviour to you component
The procedure is the same, but you would now subclass SkinnableContainer (this is usually done in pure ActionScript), write some behaviour in there, and assign the skin to an instance of this class.
public class MyComp extends SkinnableContainer {
//additional behaviour goes here
}
Usage:
<local:MyComp skinClass="MySkin">
<s:Button label='Button1' />
<s:Button label='Button2' />
</local:MyComp>

How to get the value of a ComboBox in ActionScript

I want to show the value of a ComboBox in it's Change event handler. The labelField is assigned dynamically, so that I don't know what it is when I run the event handler
cmbArea.labelField = qry.outFields[0];
I was hoping that I can have access to the value of selectedItem like:
protected function cmbArea_changeHandler(event:IndexChangeEvent):void{
// TODO Auto-generated method stub
Alert.show(event.target.selectedItem.value);
}
But it didn't work.
Any help would be much appreciated.
It's difficult to debug this without seeing your data provider code or the error message. However, it doesn't matter that the labelField is assigned dynamically. What you have will work if elements in your data provider have a property named "value". If the only property in your data provider is the one you assign as the labelField, you should be able to access it in your change handler with the following:
Alert.show(ComboBox(event.target).selectedItem);
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
import mx.controls.Alert;
import spark.events.IndexChangeEvent;
protected function comboBox_changeHandler(event:IndexChangeEvent):void
{
Alert.show(comboBox.selectedItem);
}
]]>
</fx:Script>
<s:ComboBox id="comboBox"
change="comboBox_changeHandler(event)">
<s:dataProvider>
<s:ArrayList>
<fx:String>Item 1</fx:String>
<fx:String>Item 2</fx:String>
<fx:String>Item 3</fx:String>
</s:ArrayList>
</s:dataProvider>
</s:ComboBox>
</s:Application>
I tested the following line and seems it works:
Alert.show(event.target.selectedItem[event.target.labelField]);

RichText doesn't work with bullets

See the simple application created below. I have a RichTextEditor and a RichText component. The idea is to display whatever typed in the RichTextEditor in the RichText component. Everything else (I think) works except for Bullets! The conversion works as if bullets don't exist!
<?xml version="1.0" encoding="utf-8"?>
<s:Application width="100%"
height="100%"
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<s:layout>
<s:HorizontalLayout />
</s:layout>
<fx:Script>
<![CDATA[
import flashx.textLayout.conversion.TextConverter;
import mx.events.FlexEvent;
protected function convert_clickHandler(event:MouseEvent):void
{
richText.textFlow = TextConverter.importToFlow(editor.htmlText, TextConverter.TEXT_FIELD_HTML_FORMAT);
}
]]>
</fx:Script>
<mx:RichTextEditor id="editor" />
<s:Button id="convert" click="convert_clickHandler(event)" />
<s:RichText id="richText" />
</s:Application>
Any idea on how to make Bullets work with RichText ? Am I using the correct conversion method ? TextConverter.importToFlow ?
See the image below.
List items are not a supported by TEXT_FIELD_HTML_FORMAT. You would need to create your own editor that supports the added TextFlow functionality. There is an example of one such editor in Tour de' Flex, but it was written prior to list support in TLF 2. I'm not sure if it's been updated, but if not you will need to add in that functionality yourself.
Good luck!

Flex: creating a multi column navigation bar for viewstack

I have created a Viewstack and using a Tile component and repeating LinkButtons I was able to make a multi column navigation with the viewstack as the dataprovider. My question is can this be done better? My code is below and I am wondering if I took the long way around this approach.
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<s:layout>
<s:BasicLayout />
</s:layout>
<fx:Script>
<![CDATA[
import mx.controls.Alert;
private var _listItem:Object;
private var n:int=0;
public function get listItem():Object
{
return this._listItem;
}
public function set listItem(listItem:Object):void
{
try{n++;
this.changeSelection(this._listItem);
}catch(e:Error){}
if(n==1 || n > this.viewStack.length){
this._listItem = listItem;
this.changeSelection(listItem);
}
}
private function setSelection(obj:Object):void{
this.viewStack.selectedIndex = this.viewStack.getChildIndex(this.viewStack.getChildByName(obj.target.getRepeaterItem().name));
this.listItem = obj.target;
}
private function checkSelection(obj:Object):void{
if(obj.target.getRepeaterItem() == this.viewStack.selectedChild){
if(this.listItem != obj.target){
this.listItem = obj.target;
}
}
}
private function changeSelection(obj:Object):void{
if(obj.getRepeaterItem() == this.viewStack.selectedChild){
obj.setStyle("color","#000000");
}else{
obj.setStyle("color","#999999");
}
}
]]>
</fx:Script>
<mx:Tile id="tiles" horizontalGap="20" verticalGap="0" y="210" direction="vertical">
<mx:Repeater id="masterList" dataProvider="{viewStack}">
<mx:LinkButton
id="btn"
label="{masterList.currentItem.label}"
click="this.setSelection(event)"
color="#999999"
creationComplete="checkSelection(event);" />
</mx:Repeater>
</mx:Tile>
<mx:ViewStack id="viewStack" height="200" width="300" backgroundColor="#000000" >
<mx:VBox id="vb1" backgroundColor="#FF0000" label="Screen One"/>
<mx:VBox id="vb2" backgroundColor="#00FF00" label="Screen Two"/>
<mx:VBox id="vb3" backgroundColor="#0000FF" label="Screen Three"/>
<mx:VBox id="vb4" backgroundColor="#00FFFF" label="Screen Four"/>
</mx:ViewStack>
</s:Application>
Looks to me like you've got navigation links that expose different and that those links change color based on which one is selected. Assuming that's the case, it sounds an awful lot like a tab-based navigation model. My approach would be to use the spark TabBar and skin the tabs to look like links. That way you can get rid of most of your code and let the tab skin handle changing the colors based on their current state. Also, you wouldn't need any of the code you have for changing the view stack since the TabBar would handle that for you. Hope that helps.

Binding custom components values

I have built a custom component using some containers and a TileList.
Now when I instantiate that component in my main Flex app, I want to get the value of the selected item in the tileList that the user clicks on. In other words, everytime the user clicks an item in the tileList, I want it to assign that selected value to a global application variable in the main flex app.
Any ideas how to do that?
Below is one way that you can listen to the change of TileList.selectedItem. I would recommend against putting this in a global variable, although if you must you could use a pattern like ModelLocator to do so.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical">
<mx:Script>
<![CDATA[
[Bindable] public var selectedItem:Object;
]]>
</mx:Script>
<mx:Binding source="listTile.selectedItem" destination="selectedItem"/>
<mx:Label text="{ selectedItem }"/>
<mx:TileList
id="listTile"
width="400"
height="300"
dataProvider="{ ['A','B','C'] }"/>
</mx:Application>

Resources