Flex - Issues with linkbar dataprovider - apache-flex

I'm having some issues displaying a linkbar.
The data I need to display is in a XML file.
However, I couldn't get the linkbar to display a xmllist (I did indeed read that you cannot set a xmlllist as a linkbar dataprovider... ). So, I'm transforming the xmllist in a array of objects.
Here is some code.
XML file:
<data>
<languages>
<language id="en">
<label>ENGLISH</label>
<source></source>
</language>
<language id="fr">
<label>FRANCAIS</label>
<source></source>
</language>
<language id="es">
<label>ESPAÑOL</label>
<source></source>
</language>
<language id="jp">
<label>JAPANESE</label>
<source></source>
</language>
</languages>
</data>
AS Code that transforms the xmllist in an array of objects:
private function init():void
{
var list:XMLList = generalData.languages.language;
var arr:ArrayCollection = new ArrayCollection;
var obj:Object;
for(var i:int = 0; i<list.length(); i++)
{
obj = new Object;
obj.id = list[i].#id;
obj.label = list[i].label;
obj.source = list[i].source;
arr.addItemAt(obj, arr.length);
}
GlobalData.instance.languages = arr.toArray();
}
Linkbar code:
<mx:HBox horizontalAlign="right" width="100%">
<mx:LinkBar id="language" dataProvider="{GlobalData.instance.languages}" separatorWidth="3" labelField="{label}"/>
</mx:HBox>
The separator is not displaying, and neither do the label.
But the array is populated (I tested it).
Thanks for any help you can provide =)
Regards,
BS_C3
#Decado
Here's the code for the linkbar I used:
<mx:LinkBar id="language"
dataProvider="{GlobalData.instance.languages}"
labelFunction="language_labelFunction"
itemClick="language_itemClick(event)"
styleName="GLBLinkBTN"
separatorColor="#FFFFFF"
separatorWidth="1"
linkButtonStyleName="HPLanguages"
/>
And here's the function for the labelfunction:
private function language_labelFunction(item:Object):String
{
return item.label;
}
Hope this helps.
Regards

This does what you're looking for. See if you can adapt it.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Array id="dataProvider">
<mx:Object id="en" label="English" />
<mx:Object id="fr" label="French" />
<mx:Object id="es" label="Espanol" />
<mx:Object id="jp" label="Japanese" />
</mx:Array>
<mx:LinkBar
horizontalCenter="0"
verticalCenter="0"
dataProvider="{dataProvider}"
labelField="label" />
</mx:Application>

I found a solution to my issue.
I used a labelfunction in the linkbar (instead of label property). Using a label function did the trick.
But I still do not quite understand why the label property wasn't working...

Related

Flex AIR compile error access of undefined property

Working through a series of Adobe AIR examples I have encountered a compilation error with one of them that I have distilled into the following demo application file
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication
xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.events.MenuEvent;
private static const MENU_DEMO:String = "Demo...";
private function onMenuItemClick(evt:MenuEvent):void
{
switch(evt.label)
{
case MENU_DEMO:
break;
}
}
]]>
</mx:Script>
<mx:VBox width="100%" height="100%" paddingBottom="5">
<mx:MenuBar id="menuBar"
width="100%"
labelField="#label"
itemClick="onMenuItemClick(event);">
<mx:XMLList>
<menuitem label="Error">
<menuitem label="{MENU_DEMO}" />
</menuitem>
</mx:XMLList>
</mx:MenuBar>
</mx:VBox>
</mx:WindowedApplication>
for which the descriptor file is
<?xml version="1.0" encoding="UTF-8"?>
<application xmlns="http://ns.adobe.com/air/application/1.0.M6">
<id>ErrorDemo</id>
<filename>ErrorDemo</filename>
<name>Error Demo</name>
<version>v0.1</version>
<description>Demo undefined property error</description>
<copyright></copyright>
<initialWindow>
<title>Error Demo</title>
<content>ErrorDemo.swf</content>
<systemChrome>standard</systemChrome>
<transparent>false</transparent>
<visible>true</visible>
</initialWindow>
</application>
Compilation produces the following output
C:\Projects\AIR\ErrorDemo>amxmlc ErrorDemo.mxml
Loading configuration file C:\Projects\flex_sdk_4.6\frameworks\air-config.xml
C:\Projects\AIR\ErrorDemo\ErrorDemo.mxml(28): Error: Access of undefined property _ErrorDemo_XMLList1.
<menuitem label="{MENU_DEMO}" />
The problem seems to be down to the use of the static const {MENU_DEMO} bound to the menuitem tag's label attribute because substituting it with text leads to no compilation error. Adobe's Using Flex 4.6 documentation states that static constants can be used as data binding sources, but maybe not in the way they're used here. Does anyone know what the problem is with using them in this way?
To clarify: replacing the bound constant reference {MENU_DEMO} with the string literal Demo... produces the following expected output. But using a string literal in place of the bound constant reference defeats the purpose of using a bound constant. Which is what seems to generate the error, and is the point of this post.
try adding [Bindable] before private static const MENU_DEMO:String = "Demo...";
it becomes:
[Bindable]
private static const MENU_DEMO:String = "Demo...";
I don't use Flex but from some research about your problem I noticed...
(1)
Your code has:
<menuitem label="{MENU_DEMO}" />
Try setting that as:
<menuitem label text="{MENU_DEMO}" />
(2)
Also since you say itemClick="onMenuItemClick(event);" shouldn't that be backed up by:
import mx.events.ItemClickEvent;
(3)
What is the expected result if your code compiled correctly?
I can't (or won't) test any Flex code so let me know if this works or errors...
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication
xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.events.MenuEvent;
import mx.events.ItemClickEvent; //add this
[Bindable]
public var MENU_DEMO:String = "Demo...";
public function onMenuItemClick(evt:MenuEvent):void //or try... (evt:MenuEvent = null):void
{
if (evt.label.text == MENU_DEMO) //untested
{
//do something here
evt.label.text = "Changed...";
}
}
]]>
</mx:Script>
<mx:VBox width="100%" height="100%" paddingBottom="5">
<mx:MenuBar id="menuBar"
width="100%"
labelField="#label"
itemClick="onMenuItemClick(event);">
<mx:XMLList xmlns="">
<menuitem label="Error" />
<menuitem label text="{MENU_DEMO}" />
</menuitem>
</mx:XMLList>
</mx:MenuBar>
</mx:VBox>
</mx:WindowedApplication>
For anyone interested in what a Flex 4 version of the mxml code looks like, here is what I came up with, following #ProgrammerDancuk's suggestion, who really should receive credit
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Script>
<![CDATA[
import mx.events.MenuEvent;
private static const MENU_DEMO:String = "Demo...";
private function onMenuItemClick(evt:MenuEvent):void
{
switch(evt.label)
{
case MENU_DEMO:
break;
}
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
<fx:XMLList id="demoMenu">
<menuitem label="Error">
<menuitem label="{MENU_DEMO}" />
</menuitem>
</fx:XMLList>
</fx:Declarations>
<mx:VBox width="100%" height="100%" paddingBottom="5">
<mx:MenuBar id="menuBar"
width="100%"
labelField="#label"
itemClick="onMenuItemClick(event);">
<mx:dataProvider>
{demoMenu}
</mx:dataProvider>
</mx:MenuBar>
</mx:VBox>
</s:WindowedApplication>

default button switcher by using event listener

I tried to make the nearest button to the clicked text input default. For this purpose, I wrote the below code.
Firstly, why is my buttonSwitcher function following behind the MouseEvent.CLICK ?
Secondly, Is there better way to do this ?
Thanks in advance
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="addListeners()">
<mx:Script>
<![CDATA[
public function addListeners():void {
a.addEventListener(MouseEvent.CLICK, buttonSwitcher);
b.addEventListener(MouseEvent.CLICK, buttonSwitcher);
}
public function buttonSwitcher(event:MouseEvent):void {
form.defaultButton = (((event.currentTarget as TextInput).id == "a") ? aButton : bButton);
}
]]>
</mx:Script>
<mx:Panel>
<mx:Form id="form">
<mx:FormItem label="a" direction="horizontal">
<mx:TextInput id="a" />
<mx:Button id="aButton" label="aButton" />
</mx:FormItem>
<mx:FormItem label="b" direction="horizontal">
<mx:TextInput id="b" />
<mx:Button id="bButton" label="bButton" />
</mx:FormItem>
</mx:Form>
</mx:Panel>
</mx:Application>
use ht ecapture phase of the event to change the buttons and maybe use the FocusEvent instead of CLICK, then you also switch buttons when use "tabs" through inputfields:
private function addListeners():void
{
a.addEventListener(FocusEvent.FOCUS_IN, buttonSwitcher, true);
b.addEventListener(FocusEvent.FOCUS_IN, buttonSwitcher, true);
}
public function buttonSwitcher(event:FocusEvent):void
{
form.defaultButton = (((event.currentTarget as TextInput).id == "a") ? aButton : bButton);
}

Rendering text in Flex in Graphics

I'm new to Flex (and Flash) and just playing around at the moment. I was using the drawing methods on a Canvas to color it blue, and wanted to draw text, however, I have an error somewhere in the code.
<?xml version="1.0" ?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%" paddingLeft="0" paddingRight="0" paddingTop="0" paddingBottom="0" enterFrame="enterFrame(event)" applicationComplete="addtext(event)">
<mx:VBox width="640" height="480">
<mx:Label id="debug" text="No debug yet." />
<mx:Button id="myButton" label="Hello World" />
<mx:Button id="myOtherButton" label="Foo Bar Baz" />
<mx:Canvas id="myCanvas" width="100%" height="100%" />
</mx:VBox>
<mx:Script>
<![CDATA[
import flash.text.engine.*;
import mx.controls.*;
public function addtext(event:Event):void
{
Alert.show("foo!");
var str:String = "Hello World.";
var format:ElementFormat = new ElementFormat();
var textElement:TextElement = new TextElement(str, format);
var textBlock:TextBlock = new TextBlock();
textBlock.content = textElement;
var textLine:TextLine = textBlock.createTextLine(null, 300);
textLine.x = 30;
textLine.y = 200;
Alert.show("baz!");
this.addChild(textLine); // Execution appears to cease here.
Alert.show("bar!");
}
public function enterFrame(event:Event):void
{
myCanvas.graphics.clear();
myCanvas.graphics.beginFill(0x66666FF);
myCanvas.graphics.drawRect(0, 0, myCanvas.width, myCanvas.height);
myCanvas.graphics.endFill();
}
]]>
</mx:Script>
</mx:Application>
The alerts get to "baz!" but not "bar!", so the error is somewhere there. Also, I've been running this in Firefox and fdb, but fdb isn't outputting anything - it's just launching a Flash player. A starting point on how to debug Flash
IMHO this is a somewhat fuzzy mix up between flash and flex.
First: I would suggest that if you would like your canvas to be blue, you'd use:
<mx:canvas backgroundColor="0x66666FF" width="100%" height="100%" />
Secondly the text layout framework (Commonly TLF) is a topic I would reccomend you skip until you are a bit more familiar with flex and flash.
The error you are having is because TextLine does not implement IUIComponent, and therefore cannot be added to a Flex container.
If you want to use TLF, you will need to add a spark component capable of handling it, to your application, ex. s:RichText or s:TextArea
Happy coding!!

Flex: Components bound to empty ArrayCollection at load time don't render as expected when the ArrayCollection is updated

I'm new to Flex and am using TileList bound to an ArrayCollection. The array collection is empty at load time, and then updates with the results from am HTTPService call. The problem is that the item renderers aren't being rendered as expected, I'm guessing because there was no data when they were first rendered at load time. Here's simplified example:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" >
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
public var myList1:ArrayCollection = new ArrayCollection();
[Bindable]
public var myList2:ArrayCollection = new ArrayCollection([{item:"foo"}, {item:"bar"}]);
public function updateMyList():void
{
myList1.source = [{item:"foo"}, {item:"bar"}];
}
]]>
</mx:Script>
<mx:Button id="myButton" label="Update My List"
click="updateMyList();"/>
<mx:TileList dataProvider="{myList1}"
direction="vertical"
width="800" >
<mx:itemRenderer>
<mx:Component >
<mx:Canvas backgroundColor="yellow" >
<mx:Label text="{data.item}" width="800" />
</mx:Canvas>
</mx:Component>
</mx:itemRenderer>
</mx:TileList>
<!-- This one renders as expected -->
<mx:TileList dataProvider="{myList2}"
direction="vertical"
width="800" >
<mx:itemRenderer>
<mx:Component >
<mx:Canvas backgroundColor="yellow" >
<mx:Label text="{data.item}" width="800" />
</mx:Canvas>
</mx:Component>
</mx:itemRenderer>
</mx:TileList>
</mx:Application>
You will notice that the second TileList whose bindings has data at load time renders as expected (800px wide), bit the first TileList is rendered is not the correct width and has scrollbars around it.
Could anyone explain why this is happening or even provide some work arounds to avoid this?
Regards,
Chris
It's likely that this section is causing the problems:
public function updateMyList():void
{
myList1.source = [{item:"foo"}, {item:"bar"}];
}
From here:
source of data in the ArrayCollection.
The ArrayCollection object does not
represent any changes that you make
directly to the source array. Always
use the ICollectionView or IList
methods to modify the collection.
This property can be used as the
source for data binding. When this
property is modified, it dispatches
the listChanged event.
So I'd probably change the line to:
myList1= new ArrayCollection([{item:"foo"}, {item:"bar"}]);
http://livedocs.adobe.com/flex/3/langref/mx/controls/TileList.html
Check the API.
Set the columnWidth and rowHeight properties like this,
<mx:TileList dataProvider="{myList1}"
direction="vertical"
width="800" columnWidth="800" rowHeight="25">
There is probably a more "proper" way to do it, but that should get you started.

Why isn't there an addAll() function available to ArrayCollections in Actionscript?

Is there any reason why there isn't an addAll() function available when using ArrayCollections in Actionscript? I've been using for loops to individually add them one at a time using addItem(). Is this common or is there a more convenient way?
I can add some historical nuance to this. Apparently, Adobe heard the Flex community and has responded. An addAll(addList:IList) method has been added to the ListCollectionView type in the Flex 3.4 SDK.
But just in case there are others who may still be looking for a one-liner equivalent that works across the board, here is my one-very-long-line go at it:
var arrColl1 = new ArrayCollection(['x','y','z']);
var arrColl2 = new ArrayCollection(['a', 'b', 'c']);
// Using Flex SDK version 3.4:
arrColl1.addAll( arrColl2 );
// Using any Flex SDK:
arrColl2.source.forEach(function(item:*, i:int, arr:Array):void { arrColl1.addItem(item); }, this);
This is essentially what the Flex implementation does, and should handle binding concerns correctly, although it is not necessarily the prettiest thing to look at.
There's no reason that it isn't there, it's just not there. If you changed your code to use a plain Array instead of an ArrayCollection, you can use the Array.concat method. Otherwise, the only option is addItem in a loop.
By way of example, try dropping this into a container. Essentially, it seems that if you have to have a one liner, creating a new ArrayCollection with the source of the original plus the new data will work, at least in the case below. Attempts to manipulate the source directly don't seem terribly useful, at least for data binding purposes (and if no data binding or events are involved, its probably better to use an array anyway).
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable] public var collection:ArrayCollection = new ArrayCollection([
2,6,4,6,7,8,9
]);
public function addToCollection():void {
collection.addItem(Number(collectionValue.text));
}
public function newCollectionWithAddition():void {
collection = new ArrayCollection(collection.source.concat(Number(collectionValue2.text)));
}
public function addToCollectionSource():void {
collection.source.push(Number(sourceValue));
}
public function addToCollectionSourceWithRefresh():void {
collection.source.push(Number(sourceValue2));
collection.refresh();
}
]]>
</mx:Script>
<mx:HBox width="100%">
<mx:PieChart width="300" height="300">
<mx:series>
<mx:PieSeries dataProvider="{ collection }" />
</mx:series>
</mx:PieChart>
<mx:PieChart width="300" height="300">
<mx:series>
<mx:PieSeries dataProvider="{ collection.source }" />
</mx:series>
</mx:PieChart>
</mx:HBox>
<mx:HBox>
<mx:TextInput id="collectionValue" />
<mx:Button label="Add To ArrayCollection"
click="addToCollection()"
/>
</mx:HBox>
<mx:HBox>
<mx:TextInput id="collectionValue2" />
<mx:Button label="Create New ArrayCollection with new value"
click="newCollectionWithAddition()"
/>
</mx:HBox>
<mx:HBox>
<mx:TextInput id="sourceValue" />
<mx:Button label="Add To ArrayCollection Source"
click="addToCollectionSource()"
/>
</mx:HBox>
<mx:HBox>
<mx:TextInput id="sourceValue2" />
<mx:Button label="Add To ArrayCollection Source with refresh"
click="addToCollectionSourceWithRefresh()"
/>
</mx:HBox>
After some more investigation, it turns out that an ArrayCollection is just a wrapper for an Array and that you have access to the array via arrcoll1.source. This allows you to call concat. I was able to remove my for loop and use this instead.
var arrColl1 = new ArrayCollection(['x','y','z']);
var arrColl2 = new ArrayCollection(['a', 'b', 'c']);
arrColl1.source = arColl1.source.concat(arrColl2.source);
If you are concatenating an array, for example selectedItems in a list, you can do this:
arrColl1.source = arrColl1.source.concat(seletedItems);

Resources