Looping through an arraylist sourced from an XML file - apache-flex

I am reading in an XML file that is shown in the attached image. I'm reading it in using URLRequest, which works properly. The next thing I'd like to do is to populate an arraylist with all of the "project" nodes. I'm converting the XML to an array, but the source is showing the project as being in the [0] node and the arraylist's length is 1.
What's the proper way to do this so I can loop through all the projects in the arraylist?
private var xmlParameters:XML
private var xmlStoryMap:XMLList;
protected function application1_creationCompleteHandler(event:FlexEvent):void
{
var params:Object;
var xmlLoader:URLLoader = new URLLoader();
xmlLoader.addEventListener(Event.COMPLETE, xmlloader_onComplete_Handler);
xmlLoader.addEventListener(IOErrorEvent.IO_ERROR,IOError_handler);
xmlLoader.load(new URLRequest("myXML.xml"));
}
protected function xmlloader_onComplete_Handler(event:Event):void
{
var loader:URLLoader = URLLoader(event.target)
xmlParameters = new XML(loader.data);
xmlStoryMap = xmlParameters.projects;
initializeMap();
}
protected function initializeMap():void
{
var testlist:ArrayList = new ArrayList();
testlist.source = convertXMLtoArray(xmlStoryMap.project);
}
private function convertXMLtoArray(file:String):Array
{
var xml:XMLDocument = new XMLDocument(file);
var decoder:SimpleXMLDecoder = new SimpleXMLDecoder;
var data:Object = decoder.decodeXML(xml);
var array:Array = ArrayUtil.toArray(data);
return array;
}

If you don't want to have a loop issue, use this instead
protected function xmlloader_onComplete_Handler(event:Event):void
{
var loader:URLLoader = URLLoader(event.target)
var xmlString:String = loader.data;
initializeMap(xmlString);
}
protected function initializeMap(xmlString:String):void
{
var testlist:ArrayList = new ArrayList();
testlist.source = convertXMLtoArray(xmlString);
}
private function convertXMLtoArray(xmlString:String):Array
{
var xmlDoc:XMLDocument = new XMLDocument(xmlString);
var decoder:SimpleXMLDecoder = new SimpleXMLDecoder();
var data:Object = decoder.decodeXML(xmlDoc);
return ArrayUtil.toArray(data.storymap.projects.project);
}

For looping through the projects,
for each(var projectXML:XML in xmlParameters.projects.project)
{
// Do operation
}

Related

How to Convert String into ArrayCollection in Flex?

Actually my Flex Application ..Sample code
private var selectedDays:String = null;
protected function selectRepeatedDays(event:MouseEvent):void
{
selectedDays = new String();
if(MON.selected==true)
{
selectedDays += "MONDAY,";
Alert.show("Monday :"+selectedDays);
}
if(TUE.selected==true)
{
selectedDays += "TUESDAY,";
}
if(WED.selected==true)
{
selectedDays += "WEDNESDAY,";
Alert.show("Monday :"+selectedDays);
}
if(THU.selected==true)
{
selectedDays += "THURSDAY,";
}
}
var arr:ArrayCollection = new ArrayCollection();
arr = selectedDays.substr(0, selectedDays.length-1).toString();
Alert.show(arr.lenth)
But it is not convert... the Alert Statement Not Prompt ..
So How to Convert This String into ArrayCollection...
Use the method split to convert the String to Array:
var array:Array = selectedDays.split(",");
Then (if needed yet) add each item of Array to the ArrayCollection:
var arr:ArrayCollection = new ArrayCollection();
for each (var str:String in array) {
arr.addItem(str);
}
use below code snippet to convert String to ArrayCollection
Convert String to Array using split method
var array:Array = selectedDays.split(",");
Convert Array to ArrayCollection
var selectedDaysArr:ArrayCollection = new ArrayCollection(array);

Flex sort array collection by inner class

I want to sort an array collection in a way that I am not sure is possible.
Usually when you want to sort you have something like this.
var dataSortField1:SortField = new SortField();
dataSortField1.name = fieldOneToSortBy;
dataSortField1.numeric = fieldOneIsNumeric;
var dataSort:Sort = new Sort();
dataSort.fields = [dataSortField1];
arrayCollection.sort = dataSort;
arrayCollection.refresh();
so if I had a class
public class ToSort {
public var int:a
}
I could type
var ts1:ToSort = new ToSort();
ts1.a = 10;
var ts2:ToSort = new ToSort();
ts2.a = 20;
var arrayCollection:ArrayCollection = new ArrayCollection([ts1, ts2])
var dataSortField1:SortField = new SortField();
dataSortField1.name = "a";
dataSortField1.numeric = true;
var dataSort:Sort = new Sort();
dataSort.fields = [dataSortField1];
arrayCollection.sort = dataSort;
arrayCollection.refresh();
This works fine. My problem is I now have inherited a class that has another class inside it and I need to sort against this as well.
For example
public class ToSort2 {
public var int:a
public var ToSortInner: inner1
}
public class ToSortInner {
public var int:aa
public var int:bb
}
if a is the same in multiple classes then I want to sort on ToSortInner2.aa Is this possible. I have tried to pass in inner1.aa as the sort field name but this does not work.
Hope this is clear. If not I'll post some more code.
Thanks
You need to write a custom sort compareFunction. You can drill down into the objects properties inside the function.
Conceptually something like this:
public function aSort(a:Object, b:Object, fields:Array = null):int{
if(a.aa is b.aa){
return 0
} else if(a.aa > b.aa) {
return 1
} else{
return -1
}
}
When you create your sort object, you can specify the compare function:
var dataSort:Sort = new Sort();
dataSort.compareFunction = aSort;
arrayCollection.sort = dataSort;
arrayCollection.refresh();
Sort also has another property, compareFunction.

Flex 3: Setting one arrayCollection to another is stalling the application

I'll just go ahead and C/P the entire function to ensure you guys see everything going on:
public function directorsPrepsToShow():void
{
var tempDPrepsAC:ArrayCollection = new ArrayCollection;
var dprepSD:Date = new Date;
var dprepED:Date = new Date;
var viewSD:Date = rightDate(startViewDate.getMonth(), startViewDate.getDate(), startViewDate.getFullYear());
var viewED:Date = rightDate(viewSD.getMonth(), viewSD.getDate() + 14, viewSD.getFullYear());
var newACIDs:String = new String;
var useACIDs:String = new String;
for each (var item:Object in dPrepAC)
{
dprepSD = textToDate(item[2]);
dprepED = rightDate(dprepSD.getMonth(), Number(dprepSD.getDate() + (item[3] - 1)), dprepSD.getFullYear());
if (dateCollider(dprepSD, dprepED, viewSD, viewED))
tempDPrepsAC.addItem(item as Array);
}
if (tempDPrepsAC.length != usePrepAC.length)
{
usePrepAC = new ArrayCollection();
usePrepAC = tempDPrepsAC;
Alert.show("HI");
}
}
This function is in a separate file, that's called from the main mxml via the following:
<mx:Script source="functions/dprep.as" />
The line that's causing the app to stall is "usePrepAC = tempDPrepAC;". usePrepAC is declared in the main mxml like this:
[Bindable] public var usePrepAC:ArrayCollection = new ArrayCollection;
Dose anybody see why this one line would cause the application to stall? If I comment out that line, the application loads fine (loads everything except for the information that this AC should contain). I've been looking at this now for about an hour, trying different ways to get the contents of tempDPrepsAC into usePrepAC - but nothing is working. I tried googling it, but found nothing :(
Thanks,
Brds
EDIT
dprep AC is declared in the main mxml like this:
[Bindable] public var dPrepAC:ArrayCollection = new ArrayCollection;
And the function that populates it is as follows:
public function createDirectorsPrepCollection(e:ResultEvent):void
{
var xmlList:XMLList = XML(e.result).directorsprep;
var dupString:String = "|";
var tempArray:Array = new Array;
for (var i:int = 0; i < xmlList.length(); i++)
{
if (dupString.indexOf(String("|" + xmlList[i].name.#id) + "|") == -1)
{
tempArray = new Array;
tempArray[0] = xmlList[i].prepDBID;
tempArray[1] = xmlList[i].projectDBID;
tempArray[2] = xmlList[i].startdate;
tempArray[3] = xmlList[i].numdays;
tempArray[4] = xmlList[i].positions;
dPrepAC.addItem(tempArray);
dupString += "|" + xmlList[i].prepDBID + "|";
}
}
directorsPrepsToShow();
}
This function is called by this:
<mx:HTTPService id="dprepHttp" url="{dprepXML}" resultFormat="e4x" makeObjectsBindable="true" result="createDirectorsPrepCollection(event)" />
dPrepAC is populating fine btw... I check it in a for each loop.
Try using following code:
usePrepAC.source = tempDPrepsAC.source;

load multiple flv videos using FileReferenceList class

following is my code for loading one video using FileReference class and it works fine
[Event(name="complete",type="flash.events.Event")]
[Event(name="status",type="flash.events.StatusEvent")]
public class LocalFileLoader extends EventDispatcher
{
public function LocalFileLoader()
{}
private var file:FileReference;// = FileReference(event.target);
private var list:FileReferenceList;
public var p2pSharedObject:P2PSharedObject = new P2PSharedObject();
public function browseFileSystem():void {
file = new FileReference();
list = new FileReferenceList();
list.addEventListener(Event.SELECT, selectHandler);
list.browse();
}
protected function selectHandler(event:Event):void {
for each ( file in list.fileList ){
file.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
file.addEventListener(ProgressEvent.PROGRESS, progressHandler);
file.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
file.addEventListener(Event.COMPLETE, completeHandler);
writeText(file.name+" | "+file.size);
file.load();
}
}
protected function securityErrorHandler(event:SecurityErrorEvent):void {
writeText("securityError: " + event);
}
protected function completeHandler(event:Event):void {
writeText("completeHandler");
p2pSharedObject = new P2PSharedObject();
p2pSharedObject.size = file.size;
p2pSharedObject.packetLength = Math.floor(file.size/32000)+1;
p2pSharedObject.data = file.data;
p2pSharedObject.chunks = new Object();
var desc:Object = new Object();
desc.totalChunks = p2pSharedObject.packetLength+1;
desc.name = file.name;
p2pSharedObject.chunks[0] = desc;
for(var i:int = 1;i<p2pSharedObject.packetLength;i++){
p2pSharedObject.chunks[i] = new ByteArray();
p2pSharedObject.data.readBytes(p2pSharedObject.chunks[i],0,32000);
}
// +1 last packet
p2pSharedObject.chunks[p2pSharedObject.packetLength] = new ByteArray();
p2pSharedObject.data.readBytes(p2pSharedObject.chunks[i],0,p2pSharedObject.data.bytesAvailable);
p2pSharedObject.packetLength+=1;
writeText("----- p2pSharedObject -----");
writeText("packetLenght: "+(p2pSharedObject.packetLength));
dispatchEvent(new Event(Event.COMPLETE));
}
protected function writeText(str:String):void{
var e:StatusEvent = new StatusEvent(StatusEvent.STATUS,false,false,"status",str);
dispatchEvent(e);
}
}
the sender.mxml code is following which plays the video on the stage
private function init() : void {
fileLoader = new LocalFileLoader();
fileLoader.addEventListener(Event.COMPLETE, fileLoaded);
fileShare = new P2PFileShare();
fileShare.addEventListener(StatusEvent.STATUS,
function(event:StatusEvent):void {
writeText(event.level);
});
fileShare.connect();
}
private function fileLoaded ( event:Event ) : void {
writeText("fileLoaded");
if (fileShare.connected) {
fileShare.p2pSharedObject = fileLoader.p2pSharedObject;
fileShare.p2pSharedObject.lastIndexBegin = 0;
fileShare.p2pSharedObject.lastIndexEnd = fileShare.p2pSharedObject.packetLength-1;
fileShare.updateHaveObjects();
}
setupVideo();
// PLAY
ns.play(null);
ns.appendBytesAction(NetStreamAppendBytesAction.RESET_BEGIN);
ns.appendBytes(fileLoader.p2pSharedObject.data);
video.attachNetStream(ns);
}
private function setupVideo():void{
var nc:NetConnection = new NetConnection();
nc.connect(null);
ns = new NetStream(nc);
ns.client = this;
ns.addEventListener(NetStatusEvent.NET_STATUS,
function(event:NetStatusEvent):void{
writeText("stream: "+event.info.code);
});
video = new Video();
videoComp = new UIComponent();
videoComp.addChild(video);
this.addElement(videoComp);
}
then after this, the file.name and file.size goes to mxml page and the video is displayed on stage with name and file size
but the samething i want to do with FileReferenceList class, i am solving this problem from last 2 weeks but cant ,,, plz guide me ,,, i google so many times but no specific answer
Regards
Ammad Khan
You can use the fileList property of the FileReferenceList class to access the files that where selected. Then load() each FileReference in the list separately:
private var list:FileReferenceList;
public function browseFileSystem():void {
list = new FileReferenceList();
list.addEventListener(Event.SELECT, selectHandler);
list.browse();
}
protected function selectHandler(event:Event):void {
for each ( var file:FileReference in list.fileList) {
file.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
file.addEventListener(ProgressEvent.PROGRESS, progressHandler);
file.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
file.addEventListener(Event.COMPLETE, completeHandler);
writeText(file.name+" | "+file.size);
file.load();
}
}

How to read the Dynamic form Child data in Flex?

i created a form dynamically by adding each component in action script,
now i want to get back the text/data entered in to that each component dynamically?
private function loadAllComponents():void
{
var formItemArray:Array = new Array();
for(var i:int=0; i< Application.application.designList.length; i++)//which had the colonName, colComponet to be dispalyed,
{
var fm:FormItem = new FormItem();
fm.label = Application.application.designList.getItemAt(i).colName;
var comp:String = Application.application.designList.getItemAt(i).component;
switch(comp)
{
case "TextBox":
var ti:TextInput = new TextInput();
ti.id = Application.application.designList.getItemAt(i).component;
fm.addChild(ti);
break;
case "TextArea":
var ta:TextArea = new TextArea();
ta.id = Application.application.designList.getItemAt(i).colName;
fm.addChild(ta);
break;
case "ComboBox":
var mycb:myComboBox = new myComboBox();
mycb.getAllMasterCBData(Application.application.selectedgridItem, Application.application.designList.getItemAt(i).colName);
fm.addChild(mycb);
break;
case "DateField":
var df:DateField = new DateField();
df.id = Application.application.designList.getItemAt(i).component;
fm.addChild(df);
break;
}
myform.addChild(fm);
}
}
private function saveToDb():void // Here i wan to read all the formdata
{
var formItems:Array = myform.getChildren();
for each (var item:UIComponent in formItems)
{
if (item is TextInput)
{
var text:String = Object(item).text;
Alert.show("came here");
}
else if (item is DateField)
{
var date:Date = DateField(item).selectedDate;
}
}
}
]]>
</mx:Script>
<mx:Form id="myform" cornerRadius="5" borderColor="#B7BABC" borderStyle="solid" width="100%" height="100%" />
<mx:HBox width="100%" height="100%" >
<mx:Spacer width="120"/>
<mx:Button label=" Save " id="saveBtn" click="saveToDb()" />
</mx:HBox>
You're creating the input components in ActionScript, but based on this code you are not creating them dynamically; you're just hard coding them. With your given sample, you'll know the components you are creating at compile time.
You'll need to store a reference to the form items you create; make them public variables instead of 'var' local variables. Kind of like this:
protected var ti:TextInput ;
protected var ta:TextArea ;
protected var df:DateField;
Then in your creation method, do something like this:
ti = new TextInput();
ti.id = Application.application.designList.getItemAt(i).component;
fm.addChild(ti);
ta = new TextArea();
ta.id = Application.application.designList.getItemAt(i).colName;
fm.addChild(ta);
df = new DateField();
df.id = Application.application.designList.getItemAt(i).component;
fm.addChild(df);
myform.addChild(fm);
Then when you need to access them, just do something like this:
private function getMyformData()
{
ti.text;
ta.text;
}
If you're generating the form components at run time based on data, then store then form elements in an array of some sort.
You could also work something out by looping over all children of your container, although that wouldn't be my first approach.
Since poster posted more complete code; here are some additions. I added the protected array of all form items and in each 'switch' block; the new input element is pushed onto the array.
<mx:Script>
protected var itemsArray : Array = new Array();
private function loadAllComponents():void
{
var formItemArray:Array = new Array();
for(var i:int=0; i< Application.application.designList.length; i++)//which had the colonName, colComponet to be dispalyed,
{
var fm:FormItem = new FormItem();
fm.label = Application.application.designList.getItemAt(i).colName;
var comp:String = Application.application.designList.getItemAt(i).component;
switch(comp)
{
case "TextBox":
var ti:TextInput = new TextInput();
ti.id = Application.application.designList.getItemAt(i).component;
fm.addChild(ti);
itemsArray.push(ti)
break;
case "TextArea":
var ta:TextArea = new TextArea();
ta.id = Application.application.designList.getItemAt(i).colName;
fm.addChild(ta);
itemsArray.push(ta)
break;
case "ComboBox":
var mycb:myComboBox = new myComboBox();
mycb.getAllMasterCBData(Application.application.selectedgridItem, Application.application.designList.getItemAt(i).colName);
fm.addChild(mycb);
itemsArray.push(mycb)
break;
case "DateField":
var df:DateField = new DateField();
df.id = Application.application.designList.getItemAt(i).component;
fm.addChild(df);
itemsArray.push(df)
break;
}
myform.addChild(fm);
}
}
The sateToDb method will change to be something like this:
private function saveToDb():void // Here i wan to read all the formdata
{
var formItems:Array = myform.getChildren();
for each (var item:UIComponent in itemsArray )
{
if (item is TextInput)
{
var text:String = Object(item).text;
Alert.show("came here");
}
else if (item is DateField)
{
var date:Date = DateField(item).selectedDate;
}
}
}
]]>
</mx:Script>
Edited Response:
OK, I think I see the issue.
You're adding your data controls to FormItems and adding those to the Form. But then you're iterating over the Form's children and as if they were the data controls and not FormItems.
Without commenting on the rest of the code, have a look at what this updated function is doing to retrieve the data controls:
private function saveToDb():void
{
var formItems:Array = myform.getChildren();
for each (var item:FormItem in formItems)
{
var itemChildren:Array = item.getChildren();
for each (var control:UIComponent in itemChildren)
{
if (control is TextInput)
{
var text:String = Object(item).text;
Alert.show("TextInput");
}
else if (control is DateField)
{
var date:Date = DateField(item).selectedDate;
Alert.show("Date");
}
}
}
You can delete the formItemArray variable too, it's not needed since we're getting the list of children from the Form and FormItems.
Original response:
If you keep a reference to each of the dynamic form items in an Array you can iterate over each of them in your getMyFormData() function.
e.g.
protected var formItems:Array = new Array();
// Other class stuff here...
var ti:TextInput = new TextInput();
ti.id = Application.application.designList.getItemAt(i).component;
formItems.push(ti); // Add item to array.
fm.addChild(ti);
var ta:TextArea = new TextArea();
ta.id = Application.application.designList.getItemAt(i).colName;
formItems.push(ta); // Add item to array.
fm.addChild(ta);
var df:DateField = new DateField();
df.id = Application.application.designList.getItemAt(i).component;
formItems.push(df); // Add item to array.
fm.addChild(df);
myform.addChild(fm);
<mx:button click="getMyformData()"/>
private function getMyformData()
{
//How to get the myform Data dynamically here after validations... ? &
for each (var item:UIComponent in formItems)
{
if (item is TextInput || item is TextArea)
{
// Cast to Object to access the 'text' property without the compiler complaining.
var text:String = Object(item).text;
// Do something with the text...
}
else if (item is DateField)
{
var date:Date = DateField(item).selectedDate;
// Do something with the date...
}
// Insert additional type checks as needed.
}
}
You'll have to work out what to do with the data on your own though :)
If you are using a separate list make sure you clear out the formItems array when you're done with it so you don't have references to the items keeping them in memory unnecessarily.
Instead of keeping a separate array of form items you could also iterate over the children in the fm container. You might have to make some assumptions about the children you'd be accessing but it looks like you have control over all of the children being added so that's no problem.
I hope that helps...
:)

Resources