Access array element by string in AS3 - actionscript-3

As we know its possible to access field by name using indexer.
var obj:* = {name:"Object 1"};
trace(obj["name"]); // "Object 1"
But how to access an array element by String?
var arr:Array = new Array();
var obj:* = {items:arr};
trace(obj["items[0]"]); // Undefined

Ok, basically you want to be able to have a string be interpreted as actionscript. No elegant solution I'm afraid. You could write a parser that handles some simple syntax in a string and retrieves the value.
Here's a simple example:
var obj:Object = {
items:[1, 2, 3],
subObj: {
subitems: [4, 5, 6]
}
};
trace(getValueInObject(obj, "items[0]")); // 1
trace(getValueInObject(obj, "subObj.subitems[2]")); // 6
// takes an object and a "path", and returns the value stored at the specified path.
// Handles dot syntax and []
function getValueInObject(obj : Object, pathToValue : String) : * {
pathToValue = pathToValue.replace(/\[/g, ".").replace(/]/g, "");
var pathFractions : Array = pathToValue.split(".");
var currentObject : Object = obj;
while (pathFractions.length > 0 && currentObject != null) {
var fraction : String = pathFractions.shift();
currentObject = currentObject[fraction];
}
if (currentObject != null) {
return currentObject;
}
return null;
}

Related

How to get nested deep property value from JSON where key is in a variable?

I want to bind my ng-model with JSON object nested key where my key is in a variable.
var data = {"course":{"sections":{"chapter_index":5}}};
var key = "course['sections']['chapter_index']"
Here I want to get value 5 from data JSON object.
I found the solution to convert "course.sections.chapter_index" to array notation like course['sections']['chapter_index'] this. but don't know how to extract value from data now
<script type="text/javascript">
var BRACKET_REGEXP = /^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/;
var APOS_REGEXP = /'/g;
var DOT_REGEXP = /\./g;
var FUNC_REGEXP = /(\([^)]*\))?$/;
var preEval = function (path) {
var m = BRACKET_REGEXP.exec(path);
if (m) {
return (m[1] ? preEval(m[1]) : m[1]) + m[2] + (m[3] ? preEval(m[3]) : m[3]);
} else {
path = path.replace(APOS_REGEXP, '\\\'');
var parts = path.split(DOT_REGEXP);
var preparsed = [parts.shift()]; // first item must be var notation, thus skip
angular.forEach(parts, function (part) {
preparsed.push(part.replace(FUNC_REGEXP, '\']$1'));
});
return preparsed.join('[\'');
}
};
var data = {"course":{"sections":{"chapter_index":5}}};
var obj = preEval('course.sections.chapter_index');
console.log(obj);
</script>
Hope this also help others. I am near to close the solution,but don't know how can I get nested value from JSON.
This may be a good solution too
getDeepnestedValue(object: any, keys: string[]) {
keys.forEach((key: string) => {
object = object[key];
});
return object;
}
var jsonObject = {"address": {"line": {"line1": "","line2": ""}}};
var modelName = "address.line.line1";
var result = getDescendantPropValue(jsonObject, modelName);
function getDescendantPropValue(obj, modelName) {
console.log("modelName " + modelName);
var arr = modelName.split(".");
var val = obj;
for (var i = 0; i < arr.length; i++) {
val = val[arr[i]];
}
console.log("Val values final : " + JSON.stringify(val));
return val;
}
You are trying to combine 'dot notation' and 'bracket notation' to access properties in an object, which is generally not a good idea.
Source: "The Secret Life of Objects"
Here is an alternative.
var stringInput = 'course.sections.chapter_index'
var splitInput = stringInput.split(".")
data[splitInput[1]]][splitInput[2]][splitInput[3]] //5
//OR: Note that if you can construct the right string, you can also do this:
eval("data[splitInput[1]]][splitInput[2]][splitInput[3]]")
Essentially, if you use eval on a string, it'll evaluate a statement.
Now you just need to create the right string! You could use the above method, or tweak your current implementation and simply go
eval("data.course.sections.chapter_index") //5
Source MDN Eval docs.
var data = {
"course": {
"sections": {
"chapter_index": 5
}
}
};
var key = "course['sections']['chapter_index']";
var keys = key.replace(/'|]/g, '').split('[');
for (var i = 0; i < keys.length; i++) {
data = data[keys[i]];
}
console.log(data);
The simplest possible solution that will do what you want:
var data = {"course":{"sections":{"chapter_index":5}}};
var key = "course['sections']['chapter_index']";
with (data) {
var value = eval(key);
}
console.log(value);
//=> 5
Note that you should make sure key comes from a trusted source since it is eval'd.
Using with or eval is considered dangerous, and for a good reason, but this may be one of a few its legitimate use cases.
If you don't want to use eval you can do a one liner reduce:
var data = {"course":{"sections":{"chapter_index":5}}};
var key = "course['sections']['chapter_index']"
key.split(/"|'|\]|\.|\[/).reduce((s,c)=>c===""?s:s&&s[c], data)

actionscript 3 JSON failed to parse data

I have received a JSON data like this:
'{"result":[[["test","test"],["test","test"]],[],[],[]]}'
OR
'{"result":[
[
["test","test"],
["test","test"]
],
[],
[],
[]
]
}'
But when I try to JSON.parse(data);, it is converted to object like this:
{[[["test","test"],["test","test"]],[],[],[]]:}
Is there anyway to fix it?
ADDITIONAL:
i have traced what happen before,during,after JSON do, and the problem seems to be the parse itself, sometime it work, some time doesn't
var object:Object = {test:[[["Test","test1"],["test2"]],["test3"],[],[]]}
var stringed:String = JSON.stringify(object);
trace(stringed)//{"test":[[["Test","test1"],["test2"]],["test3"],[],[]]}
var backed:Object = JSON.parse(stringed);
for each(var thigng:String in backed){
trace(thigng, "=", backed[thigng])//Test,test1,test2,test3,, = undefined
}
var object:Object = {"test":"test3"}
var stringed:String = JSON.stringify(object);
trace(stringed)//{test:"test3"}
var backed:Object = JSON.parse(stringed);
for each(var thigng:String in backed){
trace(thigng, "=", backed[thigng])//test3 = undefined
}
A "for each...in" loop will only give you the value not the key.
What you need is the for in loop.
As you can see from the example below where you went wrong
var object:Object = {"this_is_the_key":"VALUE"}
var stringed:String = JSON.stringify(object);
var backed:Object = JSON.parse(stringed);
for each(var thigng:String in backed){
trace('KEY:', thigng, ' VALUE:' ,backed[thigng]) // KEY: VALUE VALUE: undefined
}
trace('------')
for(thigng in backed){
trace('KEY:', thigng, ' VALUE:' ,backed[thigng]) //KEY: this_is_the_key VALUE: VALUE
}
Also this is not a valid JSON string
'{"result":[[["test","test"],["test","test"]],[],[],[]]}'

need help recursive javascript function

I want to turn json string
treeNodes =[{managerid:root,Employeeid:01},
{managerid:01,Employeeid:11},
{managerid:01,Employeeid:22},
{managerid:22,Employeeid:33},
{managerid:22,Employeeid:44}];
into this json string using javascript.
json={
id:root,
children[{
id:01,
children[
{id:11},
{id:22}
]},
{
id:22,
children[
{id:33},
{id:44}
]
}
Can someone help with java script function?
I think you need something like this (I assume root is a declared variable):
var rootNode = {Employeeid:root};
var json = makeJsonNode(treeNodes, rootNode);
// Do something with "json"
// ...
function makeJsonNode(treeNodes, node){
var jsonNode = { id : node.Employeeid };
var children = [];
for(var i=0; i<treeNodes.length; i++){
if(treeNodes[i].managerid === node.Employeeid){
children.push(makeJsonNode(treeNodes, treeNodes[i]));
}
}
if (children.length > 0) jsonNode.children = children;
return jsonNode;
}

as3corelib JSON parsing problem

I have the following two routines in Flash Builder:
public function getData():void {
httpService = new HTTPService();
httpService.url = "https://mongolab.com/api/1/databases/xxx/collections/system.users/?apiKey=xxx";
httpService.resultFormat = HTTPService.RESULT_FORMAT_TEXT;
httpService.addEventListener(ResultEvent.RESULT, resultHandler);
httpService.send();
}
public function resultHandler(event:ResultEvent):void {
var rawData:String = String(event.result);
var arr:Array = JSON.decode(rawData) as Array;
Debug.log(rawData);
Debug.log(arr);
httpService.removeEventListener(ResultEvent.RESULT, resultHandler);
}
rawData is displayed as JSON data but arr is displayed as [object Object] rather than an array.
What am I doing wrong?
this
var jsonStr:String = '{"glossary": {"title": "example glossary","GlossDiv": {"title": "S"},"GlossSee": "markup"}}';
will be parsed and JSON.decode returns an Object and you can access the attributes like this:
var obj:* = JSON.decode(jsonStr);
trace(obj.glossary);
this
var jsonStr:String = '[{"title":"asd"},{"title":"asd"},{"title":"asd"},{"title":"asd"}]';
will be parsed and returns an Array (which if you trace it, will return [object Object]).
so if you don't know what data is returned you could just check if
var result:* = JSON.decode(jsonStr);
if (result.length != undefined) {
// array
var arr:Array = result as Array;
}
else {
// object
var obj:Object = result as Object;
}
a try/catch around decode would also be good, because you don't know if the jsonStr is well-formed...
cheers

AS3: indexOf() sub-array in a multi-dimensional array

var asdf:Array = [ [1,1] ];
trace( asdf.indexOf( [1,1] ) ); // -1
Why can't indexOf() find the [1,1] array?
Here is a little function I wrote a while ago that works great. I included a lot of comments and an example search/function to output the results.
// set up a multidimensional array that contains some data
var myArray:Array = new Array();
myArray.push(["granola","people... are great"," 4 ","10"]);
myArray.push(["bill","orangutan","buster","keaton"]);
myArray.push(["steve","gates","24","yes, sometimes"]);
myArray.push(["help","dave","jobs","hal"]);
// here we set up some properties on the array object to hold our search string and our results
myArray.myTarget = "steve";
myArray.myResults = [];
// now we call the search
myArray.forEach(multiSearch);
// this is the function that does all the heavy lifting....
function multiSearch(element:*, index:int, array:Array)
{
// see if we have a match in this array and pass back its index
for(var i:* in element)
{
if( element[i].indexOf( array.myTarget ) > -1 )
{
var tempArray:Array = array.myResults;
tempArray.push([index,i]);
array.myResults = tempArray;
}
}
}
// -------------------------------------------------------------------------------
// all the code below is OPTIONAL... it is just to show our results
// in the output window in Flash so you know it worked....
var printArray:Array = myArray.myResults;
for(var i:* in printArray)
{
trace("TARGET FOUND #: "+printArray[i][0]+", "+printArray[i][1]+" = "+myArray[ printArray[i][0] ][ printArray[i][1] ]);
}
// -------------------------------------------------------------------------------
It fails because when you do a [x,y] you are creating a new array, adsf contains one array and indexOf search for another one.
try:
trace([1,1] == [1,1]);
You will see that it prints false, since array are compare by reference.
One quick indexOf function, arrange it to suit your needs:
function isElmEquals(e1:*, e2:*):Boolean {
return (e1==e2);
}
function isArrayEquals(a1:Array, a2:Array):Boolean {
if (a1==a2)
return true;
if ((a1==null) || (a2==null)) {
return false;
}
if (a1.length!=a2.length)
return false;
for (var i:int=0;i<a1.length;i++){
if (!isElmEquals(a1[i], a2[i]))
return false;
}
return true;
}
function indexOf(value:Array, into:Array):int{
var i:int = -1;
into.some(
function(item:*, index:int, array:Array):Boolean {
if (isArrayEquals(item as Array, value)) {
i = index;
return true;
}
return false;
}
);
return i;
}
var i:int=indexOf([1,1], [[-1,1], [0,1], [1,1], [1,-1]]);
trace(i);
var j:int=indexOf([1,2], [[-1,1], [0,1], [1,1], [1,-1]]);
trace(j);
this works. probably because the inner array is typed.
var qwer:Array = [1,1];
var asdf:Array = [qwer];
trace( asdf.indexOf( qwer ) ); // 0