Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recursive iteration over dynamically nested object array

I am using angular JS and one of their examples:http://jsfiddle.net/furf/EJGHX/

I need to take the data when the update function occurs and add some values to it before I send to the server. (If doing this with angular instead of js would be better let me know)

I'm trying to get the 'parentid' and the 'index' and update the children.

Here is the data I'm looping through

{
    "children": [{
        "id": "5",
        "parentid": "0",
        "text": "Device Guides",
        "index": "1",
        "children": [{
            "id": "10",
            "index": "0",
            "text": "Grandstream GXP-21XX"
        }, {
            "id": "11",
            "index": "1",
            "text": "Polycom Soundstation/Soundpoint"
        }, {
            "id": "23",
            "index": "2",
            "text": "New Polycom"
        }]
    }, {
        "id": "6",
        "parentid": "0",
        "text": "Pre-Sales Evaluation",
        "index": "0",
        "children": []
    }, {
        "id": "7",
        "parentid": "0",
        "text": "Router Setup Guides",
        "index": "2",
        "children": [{
            "id": "9",
            "index": "0",
            "text": "Sonicwall"
        }, {
            "id": "12",
            "index": "1",
            "text": "Cisco"
        }]
    }, {
        "id": "9",
        "parentid": "7",
        "text": "Sonicwall",
        "index": "0",
        "children": []
    }, {
        "id": "10",
        "parentid": "5",
        "text": "Grandstream GXP-21XX",
        "index": "0",
        "children": []
    }, {
        "id": "11",
        "parentid": "5",
        "text": "Polycom Soundstation/Soundpoint",
        "index": "1",
        "children": []
    }, {
        "id": "12",
        "parentid": "7",
        "text": "Cisco",
        "index": "1",
        "children": []
    }, {
        "id": "15",
        "parentid": "0",
        "text": "Post-Sales Implementation Check List",
        "index": "7",
        "children": [{
            "id": "16",
            "index": "0",
            "text": "Porting and New Number Details"
        }, {
            "id": "18",
            "index": "1",
            "text": "Partner Setup"
        }, {
            "id": "19",
            "index": "2",
            "text": "test"
        }, {
            "id": "21",
            "index": "3",
            "text": "test"
        }]
    }, {
        "id": "16",
        "parentid": "15",
        "text": "Porting and New Number Details",
        "index": "0",
        "children": []
    }, {
        "id": "18",
        "parentid": "15",
        "text": "Partner Setup",
        "index": "1",
        "children": []
    }, {
        "id": "19",
        "parentid": "15",
        "text": "test",
        "index": "2",
        "children": []
    }, {
        "id": "20",
        "parentid": "0",
        "text": "test",
        "index": "11",
        "children": []
    }, {
        "id": "21",
        "parentid": "15",
        "text": "test",
        "index": "3",
        "children": []
    }, {
        "id": "23",
        "parentid": "5",
        "text": "New Polycom",
        "index": "2",
        "children": []
    }, {
        "id": "24",
        "parentid": "0",
        "text": "Test Markup",
        "index": "14",
        "children": []
    }, {
        "id": "25",
        "parentid": "0",
        "text": "test",
        "index": "15",
        "children": []
    }]
}

This is how I'm currently looping through it, but it only gets the first dimension

for (i = 0, l = data.length; i < l; i++) {
    parentid = data[i].id == null ? '0' : data[i].id;
    data[i].index = i;
    if (data[i].children) {
        if (data[i].children.length > 0) {
            for (q = 0, r = data[i].children.length; q < r; q++) {
                data[i].children[q].parentid = parentid;
                data[i].children[q].index = q;
            }
        }
    }
}

I found this one on another fiddle, but I don't know how I would grab the parentid or the index

$.each(target.children, function(key, val) { recursiveFunction(key, val) });

    function recursiveFunction(key, val) {
        actualFunction(key, val);
        var value = val['children'];
        if (value instanceof Object) {
            $.each(value, function(key, val) {
                recursiveFunction(key, val)
            });
        }

    }


function actualFunction(key, val) {}
like image 857
Stephen Avatar asked Apr 17 '13 13:04

Stephen


2 Answers

If I'm understanding you correctly, you want each 'child' to have a parentID (defined by its parent; 0 otherwise) and an index (based on its position within it sibling set).

function normalize(parent) {
    if (parent && parent.children) {
        for (var i = 0, l = parent.children.length; i < l; ++i) {
            var child = parent.children[i];
            child.index = i;
            if (!child.parentId) child.parentId = parent.id || '0';
            normalize(child);
        }
    }
}

normalize(data);
like image 190
Andrew Avatar answered Nov 07 '22 04:11

Andrew


Recursion is calling function inside the same function. Your sample is not a recursion at all;

function runRecursive(input) {
    for (var i = 0, l = input.length; i < l; i++) {
        var current = input[i];

        parentid = current.id == null ? '0' : current.id;
        current.index = i;
        if (current.children && current.children.length > 0) {
            runRecursive(current.children);
        };
    };
};

runRecursive(data.children);

Also you should define i and l with var keyword, otherwise it will be located in window context and recursion logic will broken. Though I don't get what is parentid variable for and why it defined outside visible code.

like image 3
Tommi Avatar answered Nov 07 '22 03:11

Tommi