jQuery recursive iteration over objects

42,125

Solution 1

The .find('selector') method is basically a recusive version of .children(), and will find any descendant object that matched the selector, as opposed to .children() which only finds objects in the first level of descendants.

2nd EDIT (I phrased badly the first time, and messed up the code a bit!):

Ok, I don't think this functionality as a flag would make sense: you can quite happily recurse through that object forever (believe me, I broke firefox doing it), so you need some sort of interaction to make sure you only recurse when the child object is a valid recursion candidate.

What you need to do is simply split the function like so:

var myobj = {
  obj1: {
    key1: 'val1',
    key2: 'val2'
  },
  obj2: {
    key1: 'val1',
    key2: {
      nest1: 'val1',
      nest2: 'val2',
      nest3: 'val3'
    }
  },
  obj3: {
    key1: 'val1',
    key2: 'val2'
  }
}

$jQuery.each(myobj, function(key, val) {
  recursiveFunction(key, val)
});

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

}

function actualFunction(key, val) {
  /// do stuff
}

Solution 2

A slightly simlified version of @Ed Woodcock's version above. They way I needed to use this was to output an HTML bulleted list with named links.

var list = "<ul>";
$.each(data, recurse);

function recurse(key, val) {
    list += "<li>";
    if (val instanceof Object) {
        list += key + "<ul>";
        $.each(val, recurse);
        list += "</ul>";
    } else {
        list += "<a href='" + val + "'>" + key + "</a>";
    }
    list += "</li>";
}
list += "</ul>";

$("#container").html(list);

Solution 3

you can do this much easier as such

$(this).children().each(function(index, element) {
...
});
Share:
42,125
user113716
Author by

user113716

Updated on December 31, 2020

Comments

  • user113716
    user113716 over 3 years

    The other day I thought I saw an object iterator in jQuery that had a flag that could be set to recursively iterate over child objects. I thought it was part of jQuery.each(), but now I don't see that capability in the docs.

    Is there any such iterator in jQuery that can be automatically recursive?

    (I know how to do it in javascript. Just wondering if I actually saw what I thought I saw.)

    Thanks much!

    EDIT: To be clear, I was thinking of a utility method like jQuery.each() that will iterate recursively over javascript objects and their nested objects.

    Given the example below, the each() method would iterate over all objects, including the nested one in myobj.obj2.key2.

    I could have sworn that I saw something in jQuery docs about that, but now I can't find it.

    Thanks.

    var myobj = {
        obj1: {key1:'val1', key2:'val2'},
        obj2: {key1:'val1', key2: {nest1:'val1', nest2:'val2', nest3:'val3'}},
        obj3: {key1:'val1', key2:'val2'}
    }
    
    $jQuery.each(myobj, function(key,val) {
        // Code to run over each key/val pair
        // Does so recursively to include all nested objects
    })
    
  • user113716
    user113716 over 14 years
    Sorry Ed, I wasn't clear. I mean a utility like jQuery.each() that recursively iterates over javascript objects. Not over the DOM.
  • Ed James
    Ed James over 14 years
    No worries, I'm having a looksy myself now, this could be quite good functionality to have (for trees and stuff)
  • user113716
    user113716 over 14 years
    Hi Ed. Could you please explain what you mean about the issue with different types? It would seem to me that it would rely on different types in order to detect the presence of an object. Also, I'm a little confused by the if() statement part of your answer, probably because I'm not thinking of the DOM at all. Rather just a javascript utility for behind the scenes sort of stuff (though it could, of course, interact with the DOM when you need it). Thanks.
  • Ed James
    Ed James over 14 years
    well, in theory a string can act like a KVP, so you'd recurse infinitely without the if statement (I just used completely the wrong code: I shouldn't be allowed near a computer when I've not eaten ;) ) See if that's any better for you.
  • user113716
    user113716 over 14 years
    Yes, I see. And I knew how to recursively iterate as you did. I just thought that I saw that ability documented somewhere for jQuery. Imagine a $.each() method where you pass in the set of objects to be iterated, the function that would be executed on each pair, and a flag telling it to be recursive. If that flag is set, it would then call an if() statement during each iteration to test for an Object as your code did. It would just all be hidden in the $.each(). Now go eat a cookie! ;o)
  • Ed James
    Ed James over 14 years
    Haha, I'm well aware you know how to, you said in the OP, I just thought I'd illustrate my point with some code. I think there'd be situations where this is too difficult for an inbuilt method, and that in general it'd be more sensible to just write the code yourself: that way you can deal with things like the fact that val['key2'] won't work on the child elements because they're named differently! (bad example, but you get my drift)
  • user113716
    user113716 over 14 years
    Now I need a cookie! ;oP I'll let you off the hook soon, but why would naming make any difference? Couldn't it just test each 'val' to see if it is an object, then if so, start a new iteration? I wouldn't think one would need to tell it quite so explicitly which ones to test. Or am I missing some other roadblock? Thanks again.
  • Ed James
    Ed James over 14 years
    I did say the naming was a bad example! I think it could just lead to undefined behaviour when some anonymous object was passed into your each, what happens if key2 happens to be an array of integers and you try and do a string comparison on them? It would be almost trivial to implement a catch-all recursive override for each(), as we've both said, so the fact that it hasn't been done is an indicator that it's unlikely to be useful in that form, or that it would cause more headaches than it salves!
  • user113716
    user113716 over 14 years
    Ok. I see what you're saying. I guess I would assume that if a person set the flag, that they would also know and control the data stored in the objects. Anything and everything in jQuery can be misused. The point is that when used appropriately, it saves some coding. You've answered my question, though. There is no such functionality in jQuery. Thanks for your input.
  • TARKUS
    TARKUS almost 7 years
    Trying this code, but right off the bat it seem you have to know which key names are objects, not simple values: var value = val['key2'];