Sorted Object/Map in AS3 Flex? - actionscript-3

Is it possible to sort an object or have some sort of order in an object in Actionscript 3 Flex? I have an object which is created like so:
private var data:Object = new Object();
I then go on to put some keys and values into it:
this.data.someKeyOne = 0;
this.data.someKeyTwo = 1337;
this.data.someKeyThree = 123;
After that I loop through the object:
for (var dataPart:String in this.data) {
trace("Key: " + dataPart = " Value:" + this.data["dataPart"]);
}
But my issue is that the data will not be displayed in the order I initialized them in. This is frustrating as it is required to be in the order initialized.

As #helloflash said in his answer about loop through an object, and according to Adobe's definition of associative array (which is an instance of the Object class) :
An associative array, sometimes called a hash or map, uses keys instead of a numeric index to organize stored values. Each key in an associative array is a unique string that is used to access a stored value. An associative array is an instance of the Object class, which means that each key corresponds to a property name. Associative arrays are unordered collections of key and value pairs. Your code should not expect the keys of an associative array to be in a specific order.
The behavior that you got is normal and you can not get ordered keys in your case (using an Object like that).
If you don't need keys, you can do as #helloflash said in his answer, using a simple Array or Vector. Otherwise you can use an Array of objects, like this :
var obj:Object, i:int, s:String;
var data_array:Array = [
{key: 'someKeyOne', value: 0},
{key: 'someKeyTwo', value: 1337},
{key: 'someKeyThree', value: 123}
]
for(i = 0; i < data_array.length; i++){
obj = data_array[i];
trace('Key : ' + obj.key + ', Value = ' + obj.value);
}
for (s in data_array) {
obj = data_array[s];
trace('Key : ' + obj.key + ', Value = ' + obj.value);
}
for each (obj in data_array){
trace('Key : ' + obj.key + ', Value = ' + obj.value);
}
// all these 3 loops give :
// Key : someKeyOne, Value = 0
// Key : someKeyTwo, Value = 1337
// Key : someKeyThree, Value = 123
Or you can use Object and then sort it into an Array like this :
var data_object:Object = new Object();
data_object.someKeyOne = {index:0, value: 0};
data_object.someKeyTwo = {index:1, value: 1337};
data_object.someKeyThree = {index:2, value: 123};
var tmp_array:Array = sort_obj(data_object);
for(i = 0; i < tmp_array.length; i++){
obj = tmp_array[i];
trace('Key : ' + obj.key + ', Value = ' + obj.value);
}
for (obj in tmp_array) {
obj = tmp_array[obj];
trace('Key : ' + obj.key + ', Value = ' + obj.value);
}
for each (obj in tmp_array){
trace('Key : ' + obj.key + ', Value = ' + obj.value);
}
function sort_obj(obj:Object):Array {
var a:Array = [];
for (var key:String in obj) {
a.push({key: key, index: obj[key].index, value: obj[key].value});
}
a.sortOn('index', Array.NUMERIC);
return a;
}
// all these 3 loops give :
// Key : someKeyOne, Value = 0
// Key : someKeyTwo, Value = 1337
// Key : someKeyThree, Value = 123
Hope all that can help you.

Adobe help about looping:
The for..in loop iterates through the properties of an object, or the
elements of an array. For example, you can use a for..in loop to
iterate through the properties of a generic object (object properties
are not kept in any particular order, so properties may appear in a
seemingly random order)
Conclusion
If you want your keys to appear in order, you must use an Array (or a Vector):
var myArray:Array = [0, 1337, 123];
for (var i:String in myArray) {
trace(myArray[i]);
}
// output: 0, 1337, 123

Related

Send unassigned JSON properties to server when using stringify i.e. retain properties name whether property value is empty/null

I have two model properties:
ng-model="category.name" mandatory field
ng-model="category.desc" optional
This is how I am sending data to the server (ASP.net)
var rdt = "{'dt':" + JSON.stringify($scope.category) + "}";
However, if an optional property has an unassigned value, the property name is not found server side and gives an error. Are there any ways to retain unassigned properties of JSON?
You have several solutions:
Solution 1: Initialize the variables in your scope for example:
$scope.category.desc = null
Solution 2: Create a function to take care of that
function ToJson(object, properties) {
var result = {};
for(var i = 0; i < properties.lenght; i++) {
var property = properties[i];
if(!object[property]) {
result[property] = null;
} else {
result[property] = object[property];
}
}
return JSON.stringify(result);
}
// And then use it like this:
var rdt = "{'dt':" + ToJson($scope.category, ["name", "desc"]) + "}";

How to get dynamic object properties

I'm receiving a Json object from a request and I would like to Iterate over its properties and do something like:
if property is equals to "EN" than get it's value.
The solutions That I saw in the web are all related with GetProperties/GetProperty methods but I tried both and none of them worked.
This should be something "simple" but I think that I'm missing something here.
//Deserializing the object
ExpandoObject deserializedContent = JsonConvert.DeserializeObject<ExpandoObject>(obj.ToString(), new ExpandoObjectConverter());
dynamic deserializedDynamicContent = deserializedContent;
//Tries
var value = deserializedDynamicContent.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
var value = deserializedDynamicContent.GetType().GetProperty("ES").GetValue();
in both cases I get zero properties.
I can only get the values if I do the code below, but this will obly me to code if a new language is added.
deserializedDynamicContent.EN,
deserializedDynamicContent.ES or
deserializedDynamicContent.PT
What Am I doing wrong here?
{
"EN":[{"Id":1,"Name":"One"},{"Id":2,"Name":"Two"},{"Id":3,"Name":"Tree"}],
"ES":[{"Id":1,"Name":"Uno"},{"Id":2,"Name":"Dos"},{"Id":3,"Name":"Tres"}],
"PT":[{"Id":1,"Name":"Um"},{"Id":2,"Name":"Dois"},{"Id":3,"Name":"TrĂªs"}]
}
I'm not sure exactly what you're trying to achieve, but since ExpandoObject implements IDictionary<string,object> you should be able to do something like this:
var expando = JsonConvert.DeserializeObject<ExpandoObject>(yourJson);
var dict = (IDictionary<string, object>)expando;
// look for a particular key...
object value;
if (dict.TryGetValue("EN", out value))
{
Console.WriteLine("Key exists!");
var list = (List<dynamic>)value;
Console.WriteLine(string.Join(",", list.Select(x => "{" + x.Id + "," + x.Name + "}")));
}
// or enumerate the entire dictionary...
foreach (var kvp in dict)
{
var list = (List<dynamic>)kvp.Value;
Console.WriteLine(
kvp.Key + ":" + string.Join(",", list.Select(x => "{" + x.Id + "," + x.Name + "}")));
}

get key of a object at index x

How to get the key at specified index of a object in Flex?
var screenWindowListObject:Object = {
'something' : 'awesome',
'evenmore' : 'crazy',
'evenless' : 'foolish'
};
I want key at index 1 i.e evenmore.
In JavaScript it can be possible by using the following code.
var keys = Object.keys(screenWindowListObject);
console.log(keys[1]); // gives output 'evenmore'
Is there any equivalent in Flex?
I have an object with unique keys. Values are not unique. I am displaying the values in DropDownList by adding them to an Array Collection. I have to get the key from the Object based on the selected index.
According to Adobe, "Object properties are not kept in any particular order, so properties may appear in a seemingly random order." Because of this, you'll have to invent your own order. This can be achieved by populating an array with your keys, and then sorting that.
function getKeyOrder(hash:Object, sortType:int = 3):Array {
// Returns an array with sorted key values.
/*
1 = CASEINSENSITIVE
2 = DESCENDING
3 = ASCENDING
4 = UNIQUESORT
8 = RETURNINDEXEDARRAY
16 = Array.NUMERIC
*/
var order:Array = [];
for (var k:String in hash) {
order.push(k);
}
var reverse:Boolean = false;
if (sortType == 3) {
reverse = true;
sortType = 2;
}
order.sort(sortType)
if (reverse) { order.reverse(); }
return order;
}
var screenWindowListObject:Object = {
'something' : 'awesome',
'evenmore' : 'crazy',
'evenless' : 'foolish'
};
var orderedKeys:Array = getKeyOrder(screenWindowListObject);
for each (var key in orderedKeys) {
trace(key + ":" + screenWindowListObject[key]);
}
/* Results in...
evenless:foolish
evenmore:crazy
something:awesome
*/
trace("Index 0 = " + screenWindowListObject[orderedKeys[0]])
// Index 0 = foolish
getKeyOrder() returns an array with your keys in ascending order by default. This way, you'll be guaranteed to always have the same sequence of keys, and be able to pull up the index you're looking for. Just be wary when adding more keys, as it will shift each entry depending on where it shows up in the sort.
JavaScript's Object.keys uses the same order as a for..in loop, so in AS3 you could implement it the same way:
function getKeys(object:Object):Array {
var keys:Array = [];
for(var key in object){
keys.push(key);
}
return keys;
}
Note, though, that the enumerable order of keys on an object at runtime is not necessarily the same as you've written it in code.

How to access name of key in dynamically created json in action script 3

I have a json object coming from my java code as string :
{
"ABC":["ABC","XYZ","pqr"],
"OMG":["ABC","XYZ","pqr"],
"Hello":["ABC","XYZ","pqr"]
}
on decoding it as
myObj : Object = JSON.decode(result);
Now how do I access key names like ABC, OMG, HELLO...??
Try this will help you.
When you want properties in object use for-in loop or you want value use foreach statement.
var obj:Object = {
"ABC":["ABC","XYZ","pqr"],
"OMG":["ABC","XYZ","pqr"],
"Hello":["ABC","XYZ","pqr"]
};
var jsonText:String = JSON.stringify(obj);
var jsonObj:Object = JSON.parse(jsonText);
for(var key:String in jsonObj){
Alert.show("Key is"+key + " value is "+ jsonObj[key]);
}
Your case exactly
var myObj:Object = JSON.decode(result);
for(var key:String in myObj){
Alert.show("Key is"+key + " value is "+ myObj[key]);
}

Issue while converting actionscript object into XML

I'm new to flex. I'm trying to convert a complex object into an XML.
I'm facing a problem when i'm trying to traverse through the object. here i'm adding the code snippet.
Creating Employee Object
var result:String = new String();
employeeDept = new EmployeeDept();
employee = new Employee();
employee.employeeId = "56789";
employee.employeeName = "XYZ";
//tempString = tempString + "--- Step n ---";
/*employee.employeeDept.deptId = "2";
employee.employeeDept.deptName = "APPLE";*/
employeeDept=new EmployeeDept();
employeeDept.deptId = "3";
employeeDept.deptName = "MS";
employee.employeeDept.addItem(employeeDept);
employeeDept=new EmployeeDept();
employeeDept.deptId = "2";
employeeDept.deptName = "APPLE";
employee.employeeDept.addItem(employeeDept);
empCollection.addItem(employee);
Calling converter method on employee object
recursive(employee, "ShopServiceLifeCycleArtifacts");
Converter method
public function recursive(obj:Object, str:String):String
{
try
{
var xml:XML=new XML('<' + str + '></' + str + '>' );
if(obj is Array && obj.length!=0)
{ //tempString = tempString + "--- Recursive IF Loop---" + obj.length;
var ac:ArrayCollection=new ArrayCollection(obj as Array);
var xml2:XML=new XML(<dept></dept>);
for (var i:Number=0; i<ac.length; i++)
{
var myObj:Object=ac.getItemAt(i);
for (var prop:String in myObj)
{
xml2.appendChild(new XML("<" + prop + ">" + myObj[prop] + "</" + prop + ">"));
}
}
xml.appendChild(xml2);
} else {
if (obj==null)
tempString = tempString + "--- Obj is null ---";
else
{
tempString = tempString + "--- Obj is not null ---";
}
for (var property:String in obj)
{
tempString = tempString + property;
if(obj[property] is Array)
{
tempString = tempString + "--- obj[property] is Array---";
xml.appendChild(recursive(obj[property] as Array, property));
} else {
tempString = tempString + "--- obj[property] is not Array---";
xml.appendChild(XML("<" + property + ">" + obj[property].toString() + "</" + property + ">"));
}
}
}
}catch(e:Error)
{
return tempString+"----------"+e.message;
}
tempString = tempString +xml.toString();
return xml.toString();
}
}
But the issue now is, my employee object is not an array so it will go to else block. I'm check whether the object is null. Object is not null.
I'm going to next step i.e. for loop
for (var property:String in obj){
here comes the issue. Its not going into this for loop & returning null. :(
instead of creating employee object in an action script file & geting a instance of that employee in here if i declare & define an employeeName object here only then the logic is working. i will show that code also.
else {
//tempString = tempString + "--- Recursive Else Loop---";
var employeeNew:Object = {employeeId:"123", employeeName:"San Francisco",
empDept :[{empDeptId:"12345", empDeptName:"XYZ"},{empDeptId:"54568", empDeptName:"ABC"}]};
for (var prop:String in employeeNew) {
//trace("myObject."+prop+" = "+employeeNew[prop]);
if(employeeNew[prop] is Array)
{
xml.appendChild(recursive(employeeNew[prop] as Array, prop));
} else {
tempString = tempString + "--- obj[property] is not Array---";
xml.appendChild(XML("<" + prop + ">" + employeeNew[prop].toString() + "</" + prop + ">"));
}
}
If i use this object its able to convert it into XML. Plz do let me know what is the mistake i'm doing here because of which i'm not able to traverse through the object.
Thanks in Advance.
The for ... in loop only works on dynamic properties of objects. A dynamic property is one that can be added to the object/class at run time.
Your second approach works because you are iterating over an actual Object to which you have added properties to.
The first example does not work because you are iterating over an Employee object. The employee class is not marked as dynamic, and therefore it you cannot add additional properties to it. Even if you made it dynamic (which has a performance impact), it would only iterate over the additional properties that you added at run time, not the properties you define in the class.
One solution to this type of problem is to use describeType():
looping through object property names in actionscript
http://www.actionscript.org/forums/showthread.php3?t=183820