How to handle pre-set value in Flex Combobox as selected item - apache-flex

I'm facing a pretty basic but irksome problem with my Flex program.
To make the long story short, I've a DataGrid where in every row (you can already add and remove rows dinamically) there's a Combobox based on an ArrayCollection of elements (responsabili), every change to the Combobox already stores changes to the db.
I want the Combobox to show the value loaded from the db as the selected value.
<s:Panel title="qqq" width="100%" height="100%" styleName="light">
<s:layout>
<s:VerticalLayout paddingBottom="10" paddingLeft="10" paddingRight="10" paddingTop="10" />
</s:layout>
<s:VGroup width="100%" height="100%">
<mx:Text text="www" />
<components:GraphicButton styleName="add" toolTip="Aggiungi elemento" id="aggCompito" click="aggCompito_clickHandler(event)"/>
<s:DataGrid width="100%" height="100%" dataProvider="{MyModel.instance.compiti}" editable="true" gridItemEditorSessionSave="changeHandler(event)">
<s:columns>
<s:ArrayList>
<s:GridColumn headerText="Responsabile" editable="false" width="180">
<s:itemRenderer>
<fx:Component>
<s:GridItemRenderer>
<fx:Script>
<![CDATA[
import it.aaa.frontend.model.MyModel;
import mx.binding.utils.ChangeWatcher;
import mx.collections.ArrayCollection;
import mx.controls.Alert;
import mx.core.FlexGlobals;
import mx.events.CloseEvent;
import mx.events.IndexChangedEvent;
import spark.events.IndexChangeEvent;
protected function changeHandler(event:IndexChangeEvent):void {
data.responsabile = myResponsabile.selectedItem;
// TODO Auto-generated method stub
data.tipo = event.newIndex;
dispatchEvent(new Event("compitiChange", true));
}
protected function responsabililabelFunc(item:Object):String {
return String(item.cognome) + " " + String(item.nome);
}
protected function guessSelectedItem(item:Object):int {
return item.responsabile.id;
}
]]>
</fx:Script>
<s:HGroup>
<s:ComboBox id="myResponsabile"
dataProvider="{MyModel.instance.responsabili}"
change="changeHandler(event)"
labelFunction="responsabililabelFunc"
selectedItem="{data.responsabile}"
/>
</s:HGroup>
</s:GridItemRenderer>
</fx:Component>
</s:itemRenderer>
</s:GridColumn>
</s:ArrayList>
</s:columns>
</s:DataGrid>
</s:VGroup>
</s:Panel>
MyModel.as
public var responsabili:ArrayCollection; //initialized with actual ArrayCollection of "responsabili", with id, cognome, nome.

It will only work with selectedItem="{data.responsabile}" if you are using some actionscript classes as your data object and the property resposabile is marked as bindable:
[Bindable] public var responsabile:Object;
If you have just some generic objects as data, you will need to catch this up where data is set in your itemrenderer. So your GridItemRenderer needs another method:
override public function set data(value:Object):void
{
super.data = value;
// only do something if the data is set. When the renderer is destroyed the data will be null
if (data)
{
myResponsabile.selectedItem = data.responsabile;
}
}
I don't remember though if the data is set after all components (including your combobox) has been created or before that. So in case you will get a null pointer exception because myResponsabile is null at this point, it will get more complicated:
private var _myResponsabile:Object;
private var _myResponsabileChanged:Boolean;
override public function set data(value:Object):void
{
super.data = value;
// only do something if the data is set. When the renderer is destroyed the data will be null
if (data)
{
_myResponsabile = data.responsabile;
_myResponsabileChanged = true;
invalidateProperties();
}
}
override protected function commitProperties():void
{
super.commitProperties();
if(_myResponsabileChanged)
{
_myResponsabileChanged = false;
myResponsabile.selectedItem = _myResponsabile;
}
}

Related

BusyIndicator is not shown

I want to show the busyIndicator before launching a HTTPService , and hide it when the rpc is finished :
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark"
title="Saisie et envoi"
creationComplete="creationCompleteHandler(event)" >
<fx:Declarations>
<!-- Placer ici les éléments non visuels (services et objets de valeur, par exemple). -->
<mx:HTTPService id="userRequest" url="{url}/crr.php" resultFormat="text" result="userRequest_resultHandler(event)" useProxy="false" method="POST" />
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
import mx.rpc.events.ResultEvent;
import model.Config;
import model.Db;
var conf:Config = new Config();
public var db:Db = new Db();
[Bindable]
public var url:String = conf.getConfigSo("url"); // example : http://localhost/myfolder
protected function enregistrer(event:MouseEvent):void
{
var param:Object = new Object();
try {
if (db.avoirAttribut("enreg")) {
db.setDbSo("enreg", db.getDbSo("enreg")+chp1.text+";"+chp2.text+"\n");
}
else {
db.setDbSo("enreg", chp1.text+";"+chp2.text+"\n");
}
param.text = "Enregistrement effectué avec succès !";
navigator.pushView(Message, param);
}
catch (e:Error) {
param.text = "Enregistrement non effectué !";
navigator.pushView(Message, param);
}
}
protected function lire(event:MouseEvent):void
{
area.text = db.getDbSo("enreg");
}
protected function send(event:MouseEvent):void
{
busy.visible = true;
userRequest.cancel();
var params:Object = new Object();
params.col1 = db.getDbSo("enreg");
userRequest.send(params);
busy.visible = false;
}
protected function userRequest_resultHandler(event:ResultEvent):void
{
resultHTTP.text = userRequest.lastResult.toString();
}
protected function creationCompleteHandler(event:FlexEvent):void
{
chp1.setFocus();
}
]]>
</fx:Script>
<s:Scroller width="100%" height="100%">
<s:VGroup width="100%" height="100%" paddingTop="5" paddingBottom="5" verticalAlign="middle" horizontalAlign="center" gap="5">
<s:TextInput id="chp1" width="50%"/>
<s:TextInput id="chp2" width="50%"/>
<s:Button label="Enregistrer" click="enregistrer(event)"/>
<s:Button label="Lire" click="lire(event)"/>
<s:TextArea id="area" editable="false"/>
<s:Button label="Envoyer" click="send(event)"/>
<s:BusyIndicator id="busy" symbolColor="blue" visible="false" />
<s:Label id="resultHTTP"/>
</s:VGroup>
</s:Scroller>
</s:View>
The problem is that at runtime the BusyIndicator is not shown , though I realise that it took some seconds for the entire operation to complete. So why is not the BusyIndicator shown in this case ?
The HTTPService request send() returns when the request is sent, not when the response is received. So you are showing the busy indicator only for a short period of time (and actually not at all, since the rendering is done in the next display cycle...)
What you need to do is to make the indicator visible in the send function as you're doing, but hide the indicator on the result handler. (You should do this for the error handler as well, otherwise the indicator will still be visible if there was an error in the request)

How is an mx:Canvas measured when inside a renderer in Flex 3?

I'm having a sizing issue with a canvases located inside an HBox. It seems "_graphic", "_border" and "_fill" canvases (in com.example.ThingRenderer.mxml) do not get measured at the same time as all the other measurements inside the renderer. However, this problem is only observed on the first pass-through. Refer to the images for a visual... 1st image shows the state of the app after it finished loading. 2nd image represents what the screen looks like after the Populate button is clicked. 3rd image shows what happens when the stepper is incremented. The question is how come the drawing in the 3rd image doesn't get rendered once the data is populated into the table?
RendererTest.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
creationComplete="handleCreationComplete(event)"
>
<mx:Script>
<![CDATA[
import com.example.Thing;
import mx.collections.ArrayCollection;
import mx.events.FlexEvent;
import mx.events.NumericStepperEvent;
private const _thingProvider:ArrayCollection = new ArrayCollection();
private var _thing1:Thing;
protected function handleCreationComplete(event:FlexEvent):void {
_thing1 = new Thing("thingy", 0xff0000, 0.3);
_stepper.value = _thing1.ratio;
}
protected function handlePopulateClick(event:MouseEvent):void {
_thingProvider.addItem(_thing1);
}
protected function handleStepperChange(event:NumericStepperEvent):void {
_thing1.ratio = event.value;
}
]]>
</mx:Script>
<mx:VBox>
<mx:Button label="Populate" click="handlePopulateClick(event)" />
<mx:NumericStepper id="_stepper" minimum="0" maximum="1" stepSize="0.01" change="handleStepperChange(event)" />
<mx:AdvancedDataGrid dataProvider="{_thingProvider}" variableRowHeight="true" width="100%" height="100%">
<mx:columns>
<mx:AdvancedDataGridColumn headerText="Name" dataField="name" />
<mx:AdvancedDataGridColumn headerText="Display"
width="150" sortable="false"
itemRenderer="com.example.ThingRenderer"
/>
</mx:columns>
</mx:AdvancedDataGrid>
</mx:VBox>
</mx:Application>
com.exampleThingRenderer.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas
xmlns:mx="http://www.adobe.com/2006/mxml"
width="100%"
horizontalScrollPolicy="off" verticalScrollPolicy="off"
>
<mx:Script>
<![CDATA[
import mx.binding.utils.ChangeWatcher;
private var _thing:Thing;
private var _ratioWatcher:ChangeWatcher;
private var _doClearContent:Boolean;
private var _doDrawBorder:Boolean;
private var _doUpdateFill:Boolean;
override public function set data(value:Object):void {
if(value && value is Thing) {
_thing = Thing(value);
if(_ratioWatcher) {
_ratioWatcher.unwatch();
}
_ratioWatcher = ChangeWatcher.watch(_thing, "ratio", handleRatioChanged);
_doClearContent = false;
_doDrawBorder = true;
_doUpdateFill = true;
_graphic.invalidateSize();
_border.invalidateSize();
}
else {
_doClearContent = true;
_doDrawBorder = false;
_doUpdateFill = false;
}
super.data = value;
}
private function handleRatioChanged(event:Event):void {
_doUpdateFill = true;
invalidateDisplayList();
}
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
if(_doClearContent) {
_container.visible = false;
_container.includeInLayout = false;
_doClearContent = false;
}
super.updateDisplayList(unscaledWidth, unscaledHeight);
if(_doDrawBorder) {
trace("_thingContainer.width="+_container.width, "_thingGraphic.width="+_graphic.width, "_thingBorder.width="+_border.width);
_border.graphics.clear();
_border.graphics.moveTo(0, 0);
_border.graphics.lineStyle(1, _thing.color);
_border.graphics.lineTo(_border.width, 0);
_border.graphics.lineTo(_border.width, _border.height);
_border.graphics.lineTo(0, _border.height);
_border.graphics.lineTo(0, 0);
_doDrawBorder = false;
}
if(_doUpdateFill) {
_percentage.text = Math.round(_thing.ratio * 100.0) + "%";
_fill.graphics.clear();
_fill.graphics.beginFill(_thing.color);
_fill.graphics.drawRect(0, 0, _fill.width * _thing.ratio, _fill.height);
_doUpdateFill = false;
}
}
]]>
</mx:Script>
<mx:HBox id="_container" width="100%" paddingLeft="5" paddingTop="5" paddingRight="5" paddingBottom="5">
<mx:Label id="_percentage" width="45" />
<mx:Canvas id="_graphic" width="100%" height="15">
<mx:Canvas id="_border" x="0" y="0" width="100%" height="100%" />
<mx:Canvas id="_fill" x="0" y="0" width="100%" height="100%" />
</mx:Canvas>
</mx:HBox>
</mx:Canvas>
com.example.Thing.as
package com.example {
public class Thing {
[Bindable] public var name:String;
[Bindable] public var color:uint;
[Bindable] public var ratio:Number;
public function Thing(name:String, color:uint, ratio:Number) {
this.name = name;
this.color = color;
this.ratio = ratio;
}
}
}
All this happens because you can't use width and height properties in updateDisplayList, they are not updated yet. Make separate component (e.g. ThingProgressBar) and put drawing logick inside it, that will solve everything:
package
{
import mx.core.UIComponent;
public class ThingProgressBar extends UIComponent
{
private var _ratio:Number;
public function get ratio():Number
{
return _ratio;
}
public function set ratio(value:Number):void
{
_ratio = value;
invalidateDisplayList();
}
override protected function updateDisplayList(
unscaledWidth:Number, unscaledHeight:Number):void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);
graphics.clear();
if (unscaledWidth > 0 && unscaledHeight > 0)
{
graphics.lineStyle(1, 0xFF0000);
graphics.drawRect(0, 0, unscaledWidth, unscaledHeight);
graphics.beginFill(0xFF0000);
graphics.drawRect(0, 0, unscaledWidth * ratio, unscaledHeight);
graphics.endFill();
}
}
}
}
So your renderer might look like this:
<mx:HBox
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
horizontalScrollPolicy="off" verticalScrollPolicy="off" xmlns:local="*"
>
<fx:Script>
<![CDATA[
[Bindable] private var _thing:Thing;
override public function set data(value:Object):void
{
_thing = value as Thing;
super.data = value;
}
]]>
</fx:Script>
<mx:HBox width="100%"
paddingLeft="5" paddingTop="5"
paddingRight="5" paddingBottom="5">
<mx:Label text="{_thing.name}" width="45" />
<local:ThingProgressBar width="100%" height="15"
ratio="{_thing.ratio}"/>
</mx:HBox>
</mx:HBox>
I removed watcher. Binding by watcher is considered a bad practice, use mxml binding or events instead.
I removed two Canvases with separated border and fill - they can be cobined together.
I used UIComponent instead of Canvas. Don't use containers unless you need layout, they are heavy.
I used HBox instead of Canvas in renderer because I like boxes more :) But you can't avoid using second container in renderer if you need custom styles since List overwrites renderer's stylesheet.

Flex, how to exchange user names and peer IDs between all connected users

Hello I'm building a chat using Flex. The problem is how to do that new user get the list off all users online and added to the lists of all users. I try to put this information in DataGrid through dataProvider "callerns":
<s:DataGrid x="10" y="125" width="238" height="125" alternatingRowColors="[ #67676767, #555555]"
borderVisible="true" chromeColor="#555555" color="#CCCCCC"
contentBackgroundColor="#555555" dataProvider="{callerns}" fontWeight="bold"
requestedRowCount="4" rollOverColor="#08700D" selectionColor="#08700D"
symbolColor="#CCCCCC">
<s:columns>
<s:ArrayList>
<s:GridColumn dataField="name" headerText="USER ONLINE"></s:GridColumn>
<s:GridColumn dataField="peerID" headerText="USER ID"></s:GridColumn>
</s:ArrayList>
</s:columns>
</s:DataGrid>
Here is the part of code:
[Bindable]
private var callerns:ArrayCollection = new ArrayCollection();
...........
private function netStatusEvent(event:NetStatusEvent):void{
trace('NetConnection status event (1): ' + event.info.code);
//writeText(event.info.code);
switch(event.info.code){
case "NetConnection.Connect.Success":
log('Connected (NearID: '+nc.nearID+')', 'debug');
log('Connection sucsessful');
MyPeerID = nc.nearID;
txtFingerprint.text = MyPeerID;
initSendNetStream();
callerns.addItem({peerID: MyPeerID, name: myName});
setupGroup();
break;
case "NetGroup.Posting.Notify":
receiveMessage(event.info.message);
log('Message posted');
break;
case "NetGroup.Connect.Success":
log('Net Group connection sucsessful');
connected = true;
break;
case 'NetStream.Connect.Success':
log('Peer Connected (FarID: '+event.info.stream.farID+')', 'debug');
break;
case "NetGroup.Neighbor.Connect":
log('New user connected');
break;
}
}
private function initSendNetStream():void{
trace("initSendStream");
sendStream = new NetStream(nc,NetStream.DIRECT_CONNECTIONS);
sendStream.addEventListener(NetStatusEvent.NET_STATUS, netStatusEvent);
var clientObject:Object = new Object();
clientObject.onPeerConnect = function(callerns:NetStream):Boolean{
initRecvStream(callerns.farID);
callerns.send('onPeerNameUpdate', MyPeerID, myName);
return true;
}
sendStream.client = clientObject;
sendStream.publish('video');
log('Net Stream publish start');
}
private function initRecvStream(peerID:String):void {
//log('initRecvStream', 'debug');
var stream:NetStream = new NetStream(nc, peerID);
stream.addEventListener(NetStatusEvent.NET_STATUS, netStatusEvent);
stream.play('video');
var client:Object = new Object();
client.onPeerNameUpdate = onPeerNameUpdate;
stream.client = client;
var peer:Object = new Object();
peer.stream = stream;
recvStreams[peerID] = peer;
}
private function onPeerNameUpdate(peerID:String, name:String):void {
//log('onPeerNameUpdate received: '+peerID+':'+name, 'debug');
//log(name+' connected to your channel', 'debug');
callerns.addItem({peerID: peerID, name: name});
}
Unfortunately this doesn't work and new users aren't added to the grid. Could you please help me to solve this problem?
Removed original post seems I'm wrong, this works:
<?xml version="1.0" encoding="utf-8"?>
<s:Group creationComplete="group1_creationCompleteHandler(event)"
height="100%"
width="100%"
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:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.events.FlexEvent;
[Bindable]
private var callerns : ArrayCollection;
protected function group1_creationCompleteHandler(event : FlexEvent) : void
{
callerns = new ArrayCollection();
}
protected function addItemClickHandler(event : MouseEvent) : void
{
callerns.addItem({peerID: "somePeerID", name: "someName"});
}
]]>
</fx:Script>
<s:layout>
<s:VerticalLayout/>
</s:layout>
<s:Button click="addItemClickHandler(event)"
label="Add Item"/>
<s:Button click="propertyChangeClickHandler(event)"
label="Dispatch Property Change"/>
<s:DataGrid alternatingRowColors="[ #67676767, #555555]"
borderVisible="true"
chromeColor="#555555"
color="#CCCCCC"
contentBackgroundColor="#555555"
dataProvider="{callerns}"
fontWeight="bold"
height="125"
requestedRowCount="4"
rollOverColor="#08700D"
selectionColor="#08700D"
symbolColor="#CCCCCC"
width="238"
x="10"
y="125">
<s:columns>
<s:ArrayList>
<s:GridColumn dataField="name"
headerText="USER ONLINE">
</s:GridColumn>
<s:GridColumn dataField="peerID"
headerText="USER ID">
</s:GridColumn>
</s:ArrayList>
</s:columns>
</s:DataGrid>
</s:Group>
So I was originally wrong, hitting the button does cause an update to the grid. It would have been extremely helpful if you had posted a link to the original tutorial you were building off of, I found it and got it working with spark just fine. I'm assuming you got this part figured out already but here's the basic chat client:
<?xml version="1.0" encoding="utf-8"?>
<s:Application minHeight="600"
minWidth="955"
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:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
private const SERVER_ADDRESS : String = "rtmfp://p2p.rtmfp.net/";
private const DEVELOPER_KEY: String = PUT_YOUR_DEV_KEY_HERE;
private var nc : NetConnection;
private var myPeerID : String;
private var farPeerID : String;
// streams
private var sendStream : NetStream;
private var recvStream : NetStream;
private function initConnection() : void
{
if (txtFingerprint.text)
{
farPeerID = txtFingerprint.text;
}
nc = new NetConnection();
nc.addEventListener(NetStatusEvent.NET_STATUS, ncStatus);
nc.connect(SERVER_ADDRESS + DEVELOPER_KEY);
}
private function ncStatus(event : NetStatusEvent) : void
{
trace(event.info.code);
myPeerID = nc.nearID;
txtFingerprint.text = myPeerID;
}
private function initSendStream() : void
{
trace("initSendStream");
sendStream = new NetStream(nc, NetStream.DIRECT_CONNECTIONS);
sendStream.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
sendStream.publish("media");
var sendStreamClient : Object = new Object();
sendStreamClient.onPeerConnect = function(callerns : NetStream) : Boolean
{
farPeerID = callerns.farID;
trace("onPeerConnect " + farPeerID);
return true;
}
sendStream.client = sendStreamClient;
}
private function initRecvStream() : void
{
recvStream = new NetStream(nc, farPeerID);
recvStream.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
recvStream.play("media");
recvStream.client = this;
}
public function receiveSomeData(str : String) : void
{
txtReceiveData.text = str;
}
private function sendSomeData() : void
{
sendStream.send("receiveSomeData", txtSendData.text);
}
private function netStatusHandler(event : NetStatusEvent) : void
{
trace(event.info.code);
}
]]>
</fx:Script>
<mx:TextInput id="txtFingerprint"
width="391"
x="10"
y="10"/>
<mx:Button click="initConnection()"
label="Connect"
x="409"
y="10"/>
<mx:TextInput id="txtSendData"
x="10"
y="40"/>
<mx:TextInput id="txtReceiveData"
width="251"
x="10"
y="70"/>
<mx:Button click="sendSomeData()"
label="Send data"
x="178"
y="40"/>
<mx:Button click="initSendStream()"
label="initSendStream"
x="10"
y="100"/>
<mx:Button click="initRecvStream();"
label="initReceiveStream"
x="132"
y="100"/>
<mx:Text height="122"
text="Hint: First running Flash app - click Connect to get Fingerprint PeerID. Copy and paste this PeerID to second running Flash app to the same field and click Connect. Then initSendStream and initReceiveStream on both of them and finally you can write some text and click Send data."
width="391"
x="10"
y="130"/>
</s:Application>
Get a developer key here:
http://www.adobe.com/cfusion/entitlement/index.cfm?e=cirrus
I'm not sure what's going wrong but as the commenter above says you need to include how exactly it's breaking, that is what happens when you debug (be sure to install the debug flash player for whatever browser your using, beware chrome manages it's own plugin by default) what do you see in the console, do you get any errors etc. The tutorial app works fine for me, having this deal with two way communication and maintaining a list of all connected peers seems to be the goal correct? I also don't understand the question about NetGroup, there's more on P2P that covers that here though:
http://www.adobe.com/devnet/flashmediaserver/articles/p2p_rtmfp_groups.html
I wish you would have included more information about where you started and where you're headed with all this though (and code, I always want more code :)

Cannot figure out why List won't display data from ArrayCollection

I'm working on a flash cards application and am using an ArrayCollection of Objects to store each cards individual data. When the user click the 'save' button, the text from the two textAreas and the 'title' textinput are stored in the AC as one object with .title, .side1 and .side2 properties that contain the text from the flash card.
I have made a List in a separate class I want to have display the title of each card the user has created, but after days of researching and looking around, I still cannot get the display to list the titles.
If anyone could point me in the right direction it would very appreciated.
Part of my NewCard.mxml:
<?xml version="1.0" encoding="utf-8"?>
<fx:Script>
<![CDATA[
import flash.events.EventDispatcher;
import mx.collections.ArrayCollection;
import spark.effects.SlideViewTransition;
import views.MyCards;
protected function button1_clickHandler(event:MouseEvent):void // back button
{
{
navigator.pushView(views.MyFlashCardsHome, event.relatedObject);
}
}
protected function button2_clickHandler(event:MouseEvent):void // save button
{
var myc:MyCards = new MyCards();
var card:Object = new Object();
myc.add();
titleCard.text = "Card Added!";
}
protected function button3_clickHandler(event:MouseEvent):void // flip button
{
rotateEffect.play();
if(rotateEffect.isPlaying)
{
if(mtext1.visible)
{
mtext2.visible = true;
mtext1.visible = false;
//mtext2.text = "two";
groupt.layoutDirection = "rtl";
}
else
{
mtext2.visible = false;
mtext1.visible = true;
//mtext1.text = "one";
groupt.layoutDirection = "rtl";
}
}
}
protected function button4_clickHandler(event:MouseEvent):void // push home button
{
var slideViewTransition:SlideViewTransition = new SlideViewTransition( 300, SlideViewTransition.SLIDE_RIGHT);
navigator.pushView(views.HomePage, event.relatedObject, slideViewTransition);
}
]]>
</fx:Script>
<fx:Declarations>
<s:Rotate3D id="rotateEffect" duration="300" target="{groupt}"
angleYFrom="0" angleYTo="180"
autoCenterTransform="true"
effectStart="flipButton.enabled=false;"
effectEnd="flipButton.enabled=true;"/>
</fx:Declarations>
<s:actionContent>
<s:Button height="50" label="Study" click="button1_clickHandler(event)" cornerRadius="0"
fontFamily="_sans"/>
<s:Button height="62" click="button4_clickHandler(event)" cornerRadius="0" skinClass="skins.homeButtonSkin"/>
</s:actionContent>
<s:Image x="0" y="-80" width="1024" height="600" source="#Embed('mainapp1.jpg')"/>
<s:TextInput id="titleCard" x="240" y="10" height="62" chromeColor="#515851" color="#060606"
contentBackgroundAlpha="1.0" contentBackgroundColor="#FFFFFF" text="Title"/>
<s:SkinnableContainer
id = "groupt" x="161" y="88" width="703" height="357" >
<s:TextArea id="mtext2" visible="false" x="0" y="0" width="703" height="357"
color="#000000" contentBackgroundAlpha="1.0"
contentBackgroundColor="#FFFFFF" editable="true" enabled="true"
paddingTop="70" text="Enter Text Here: (Side Two)" textAlign="center"/>
<s:TextArea id="mtext1" x="0" y="0" width="703" height="357" color="#030303"
contentBackgroundAlpha="1.0" contentBackgroundColor="#FFFFFF" editable="true"
enabled="true" fontFamily="Arial" fontStyle="normal" fontWeight="normal"
lineThrough="false" paddingTop="70" text="Enter Text Here: (Side One)"
textAlign="center" textDecoration="none" verticalAlign="middle"/>
</s:SkinnableContainer>
<s:Button x="763" y="10" height="62" label="Save" click="button2_clickHandler(event)"
cornerRadius="0" fontFamily="_sans"/>
<s:Label x="5" y="34" color="#49A6D6" fontFamily="Georgia" fontStyle="italic" fontWeight="bold"
paddingLeft="25" text="My"/>
<s:Label x="68" y="34" width="73" color="#E0B338" fontFamily="Georgia" fontStyle="italic"
fontWeight="bold" paddingLeft="0" text="Flash"/>
<s:Label x="138" y="34" color="#49A6D6" fontFamily="Georgia" fontStyle="italic" fontWeight="bold"
text="Cards!"/>
<s:Button id="flipButton" x="468" y="460" height="50" label="Flip" chromeColor="#2428D8"
click="button3_clickHandler(event)" fontFamily="_sans"/>
Part of my MyCards.mxml:
<?xml version="1.0" encoding="utf-8"?>
<fx:Script>
<![CDATA[
import flash.events.IOErrorEvent;
import flash.filesystem.File;
import flash.filesystem.FileMode;
import flash.filesystem.FileStream;
import mx.collections.ArrayCollection;
import mx.collections.ArrayList;
import mx.events.CollectionEvent;
import mx.events.FlexEvent;
import spark.effects.SlideViewTransition;
import spark.events.IndexChangeEvent;
import views.NewCard;
public var file:File;
public var fileStream:FileStream;
public var fileName:String = "Initial String";
private var directory:String = "SimpleSaveFromAIR";
public var nc:NewCard = new NewCard();
public var card:Object = new Object();
[Bindable]
public var cards:ArrayCollection = new ArrayCollection();
protected function button1_clickHandler(event:MouseEvent):void // pushed home button
{
var svt:SlideViewTransition = new SlideViewTransition(300, SlideViewTransition.SLIDE_RIGHT);
navigator.pushView(views.HomePage, event.relatedObject, svt);
}
public function add():void
{
var nc:NewCard = new NewCard();
var card:Object = new Object();
card.fTitle = nc.titleCard.text; //adding text to object from NewCard.mxml class
cards.addItem(card);
}
/* public function save():void
{
file = File.documentsDirectory.resolvePath(directory + "/" + fileName);
fileStream = new FileStream();
fileStream.open(file, FileMode.WRITE);
fileStream.writeObject(cards);
fileStream.close();
} */
public function myCardsList_creationCompleteHandler(event:FlexEvent):void
{
cards.addEventListener(CollectionEvent.COLLECTION_CHANGE, refreshList);
trace(cards.list); // no data at all shows up here
}
private function refreshList(event:CollectionEvent):void
{
trace("cards refreshed "+ cards.list);
}
public function testButton_clickHandler(event:MouseEvent):void
{
card.fTitle = nc.titleCard.text;
cards.addItem(card);
//trace(cards.list); // add data that has been added shows up here
}
]]>
</fx:Script>
<s:actionContent>
<s:Button id="testButton" label="Button" click="testButton_clickHandler(event)" />
<s:Button label="Delete"/>
<s:Button label="Home" click="button1_clickHandler(event)" skinClass="skins.homeButtonSkin"/>
</s:actionContent>
<s:Image x="0" y="-80" height="603" source="mainapp1.jpg"/>
<s:List id="myCardsList" x="10" y="10" left="0" right="0" top="0" bottom="0" width="1004"
height="500" dataProvider="{cards}" labelField="fTitle"
enabled="true" >
</s:List>
Again any help is greatly appreciated.
CardVO class:
package
{
public class CardVO
{
private var _title:String; //values returned from getter/setter functions
private var _side1:String;
private var _side2:String;
//get the "Title", "Side1" and "Side2" values from textAreas (later) and set them
// above variables
public function get Title():String {return _title;}
public function set Title(value:String):void { _title = value; }
public function get Side1():String {return _side1;}
public function set Side1(value:String):void {_side1 = value;}
public function get Side2():String {return _side2;}
public function set Side2(value:String):void {_side2 = value;}
}
}
** NewCard snippet:**
[Bindable]
public var myCard:CardVO = new CardVO(); // create new instance of CardVO
....
<!-- text property of mtext1 and mtext2 is bound and returned to the get/set functions in CardVO in the 'change' event-->
<!-- change sets setter values to those retrieved from textAreas-->
<s:TextArea id="mtext2" visible="false" x="0" y="0" width="703" height="357"
color="#000000" contentBackgroundAlpha="1.0"
contentBackgroundColor="#FFFFFF" editable="true" enabled="true"
paddingTop="70" text="{myCard.Side2}" change = "{myCard.Side2 = mtext2.text}"
textAlign="center"/>
<s:TextArea id="mtext1" x="0" y="0" width="703" height="357" color="#030303"
contentBackgroundAlpha="1.0" contentBackgroundColor="#FFFFFF" editable="true"
enabled="true" fontFamily="Arial" fontStyle="normal" fontWeight="normal"
lineThrough="false" paddingTop="70" text="{myCard.Side1}" change="{myCard.Side1 = mtext1.text}"
textAlign="center" textDecoration="none" verticalAlign="middle"/>
</s:SkinnableContainer>
MyCards snippet:
public function add():void
{
var nc:NewCard = new NewCard(); // create new instance of NewCard
cards.addItem(nc.myCard); // add new Item to ArrayCollection 'cards'
trace(cards.list);
}
Mycards List code
<s:List id="myCardsList" x="10" y="10" left="0" right="0" top="0" bottom="0" width="1004"
height="500" change="myCardsList_changeHandler(event)" dataProvider="{cards}"
enabled="true" >
<s:itemRenderer>
<fx:Component>
<s:MobileItemRenderer label="{data.title}"/>
</fx:Component>
</s:itemRenderer>
</s:List>
Assuming you're using the List component you should be able to specify the field you want to show using the labelField property.
<s:List id="myFlashCardList" dataProvider="{cards}" labelField="fTitle"/>
EDIT 2:
It seems like what you're trying to do here (and correct me if I'm wrong), is to have the user create a new instance of the NewCard object and then add it to your cards ArrayCollection. Your list then displays the titles of the cards the user has created.
Assuming this is the case, I think you're making it a little complicated than it needs to be. ArrayCollections can hold any type of class or object so you don't have to create a new Object and add it to the ArrayCollection every time they add a new card.
What I would do is create a Card class and populate it using your NewCard component. When you're done, you add that Card class to the ArrayCollection. Something like this:
The CardVO class:
package
{
public class CardVO
{
private var _title:String;
private var _side1:String;
private var _side2:String;
public function get Title():String { return _title; }
public function set Title(value:String):void { _title = value; }
public function get Side1():String { return _side1; }
public function set Side1(value:String):void { _side1 = value; }
public function get Side2():String { return _side2; }
public function set Side2(value:String):void { _side2 = value; }
}
}
Then in your NewCard.mxml file you use a CardVO to store the data:
<fx:Script>
<![CDATA[
...
[Bindable] public var myCard:CardVO = new CardVO();
...
]]>
</fx:Script>
<s:SkinnableContainer id = "groupt">
<s:TextArea id="mtext2" text="{myCard.Side2}" change="{myCard.Side2 = mtext2.text}"/>
<s:TextArea id="mtext1" text="{myCard.Side1}" change="{myCard.Side1 = mtext1.text}" />
</s:SkinnableContainer>
Then after the user has created their card, you pass the CardVO object to your ArrayCollection.
...
public function add():void
{
var nc:NewCard = new NewCard();
cards.addItem(nc.myCard);
}
...
This is a very abbreviated example so feel free to ask any questions that don't make sense. You should also look into Data Binding if you haven't already done so. It will save you a lot of time and make your apps more efficient once you get the hang of it. :)

Dynamic Spark DropDownList ItemRenderer within Flex Datagrid

I have a datagrid which contains a Spark dropdownlist that needs to obtain dynamic data. The datagrid uses a separate dataProvider.
When I use a static ArrayCollection within my ItemRenderer, it works (please see listing 1).
However, when I use Swiz to mediate a 'list complete' event to load the ArrayCollection, the dropdownlist does not show the new data (please see listing 2).
Using the debugger, I inspected the dropdownlist ItemRenderer and have confirmed the new data is being loaded into the ArrayCollection. The new data is not shown in the UI control. I have tried invalidateProperties() + validateNow() and dispatching events on both the control and the renderer (this), but nothing seems to make the new data appear in the control on the datagrid.
Please help !!!
Listing 1: Datagrid and static ArrayCollection (this works):
<mx:DataGrid x="10" y="25" width="98%" id="dgInventory" paddingLeft="25" paddingRight="25" paddingTop="25" paddingBottom="25"
editable="true"
itemClick="dgInventory_itemClickHandler(event)" dataProvider="{acInventory}"
creationComplete="dgInventory_creationCompleteHandler(event)"
height="580">
<mx:columns>
<mx:DataGridColumn headerText="Item" dataField="itemName" itemRenderer="components.ItemRendererItem"
rendererIsEditor="true" editorDataField="selection" editable="true"/>
<mx:DataGridColumn headerText="Quantity Required" dataField="quantityReq" itemRenderer="components.ItemRendererQuantityRequired"
rendererIsEditor="true" editorDataField="selection" editable="true"/>
</mx:columns>
</mx:DataGrid>
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import spark.events.IndexChangeEvent;
public var selection:int;
[Bindable]
protected var acItem:ArrayCollection = new ArrayCollection(
[ { itemName: "Item1"},
{ itemName: "Item2"},
{ itemName: "Item3"},
]);
//
protected function dropdownlist1_changeHandler(e:IndexChangeEvent):void
{
selection = e.newIndex;
}
]]>
</fx:Script>
<s:DropDownList id="ddlItem" prompt="Select Item" dataProvider="{acItem}" labelField="itemName"
selectedIndex="{int(dataGridListData.label)}"
change="dropdownlist1_changeHandler(event)"
width="80%" top="5" bottom="5" left="5" right="5"/>
Listing 2: Dynamic ArrayCollection (does not work):
<?xml version="1.0" encoding="utf-8"?>
<s:MXDataGridItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
focusEnabled="true">
<fx:Script>
<![CDATA[
import event.ItemEvent;
import mx.collections.ArrayCollection;
import mx.events.FlexEvent;
import spark.events.IndexChangeEvent;
public var selection:int;
//
[Bindable]
protected var acItem:ArrayCollection = new ArrayCollection();
//
protected function dropdownlist1_changeHandler(e:IndexChangeEvent):void
{
selection = e.newIndex;
}
//
protected function ddlItem_creationCompleteHandler(event:FlexEvent):void
{
var eve : ItemEvent = new ItemEvent( ItemEvent.LIST_ITEM_REQUESTED );
dispatchEvent( eve );
}
//
[Mediate( event="ItemEvent.LIST_ITEM_COMPLETE", properties="acItem" )]
public function refreshness( _acItem : ArrayCollection ):void
{
acItem.removeAll();
var len:int = _acItem.length;
if (len > 0)
{
for (var i:int=0; i < len; i++)
{
var newItem:Object = new Object;
newItem["itemName"] = _acItem[i].itemName;
acItem.addItem(newItem);
}
}
this.invalidateProperties();
this.validateNow();
//dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE));
}
]]>
</fx:Script>
<s:DropDownList id="ddlItem" prompt="Select Item" dataProvider="{acItem}" labelField="itemName"
selectedIndex="{int(dataGridListData.label)}"
creationComplete="ddlItem_creationCompleteHandler(event)"
change="dropdownlist1_changeHandler(event)"
width="80%" top="5" bottom="5" left="5" right="5"/>
</s:MXDataGridItemRenderer>
After re-reading Peter Ent's ItemRenderer series, this turned out to be quite simple.
I extended DataGrid to have the ArrayCollection property I needed, then added this to my renderer:
[Bindable]
protected var acItem:ArrayCollection = new ArrayCollection();
//
override public function set data( value:Object ) : void
{
super.data = value;
acItem = (listData.owner as MyDataGrid).itemList; // get the data from the renderer's container (by extending it to add a property, if necessary)
}

Resources