0

Though I see lots of posts about this overall topic (best way to get child nodes) I can't find anything regarding iteration and assignment in two-layer nested children. I have seen examples online of children being called with []'s and ()'s. Thanks in advance.

Let's assume I have this HTML and want a string of all the file names (excluding URL path or file extension) inside of the "sortable" UL element.

<ul id="sortable" class="ui-sortable">
    <li class="ui-state-default">
        <img id="aImg" alt="sortable image" src="images/a.jpg" />
    </li>
    <li class="ui-state-default">
        <img id="bImg" alt="sortable image" src="images/b.jpg" />
    </li>
    <li class="ui-state-default">
        <img id="cImg" alt="sortable image" src="images/c.jpg" />
    </li>
</ul>

My JavaScript looks like this:

 var theImageOrder = "";
 var theCounter = 0;
 while (theCounter < $('#sortable').children().length) 
 {
    var theImageName = $('#sortable').children(theCounter).children(0).attr("src").toString().substring($('#sortable').children(theCounter).children(0).attr("src").toString().lastIndexOf("/") + 1, $('#sortable').children(theCounter).children(0).attr("src").toString().lastIndexOf("."));
    theImageOrder = theImageOrder + theImageName;
    theCounter++;
}

I would expect the output would be abc but instead I'm getting aaa.

Community
  • 1
  • 1
Kulingar
  • 941
  • 3
  • 14
  • 30
  • 1
    why dont you do a `$.each()` ?? – karthikr May 15 '13 at 17:59
  • 1
    Instead of `.children(theCounter)`, use `.children().eq(theCounter)`, although there are much better ways to do this than this type of looping – Ian May 15 '13 at 17:59
  • 1
    I just made a jsfiddle earlier today answering a similar question. Check [this](http://jsfiddle.net/SpYk3/RyYv6/) out! Scroll past the giant object to see the JS and you might get a better idea of how .each itterates through objects. – SpYk3HH May 15 '13 at 18:03

4 Answers4

4

An UL should have only LI children, and I'm guessing selecting images would be clever, as you're looking for the src attribute. $.map returns everyting in an array, you can choose to join it to get a string. Using > makes sure it's only direct children etc :

var images = $.map($('#sortable > li > img'), function(el,i) {
    return el.src.split('/').pop();
}).join(', ');

FIDDLE

adeneo
  • 312,895
  • 29
  • 395
  • 388
  • I forgot to mention, I'm dynamically forming the HTML for the images that appear in the "sortable" UL so I don't really know how many there nor what their names might be. Also, I don't believe I'm violating the (Only LI in UL) unless you're saying I shouldn't put IMG tags inside of LI tags, if that's the case can you link me something that supports that? – Kulingar May 15 '13 at 18:40
  • 1
    @Kulingar - You can put anything inside an UL, but usually only LI as direct children, everything else should be nested inside the list items (LI). It does'nt really matter how many images there are, as long as they are direct children of LI elements that themselves are direct children of the sortable UL. You used children() in your code in the question, wich finds only direct children, so I assumed that was what you wanted, if not, just remove the `>`sign in the selector. – adeneo May 15 '13 at 18:57
4
var files = $('#sortable img').map(function(){
     return this.src.split('/').pop();
}).get();

http://jsfiddle.net/uyQXP/

Ram
  • 143,282
  • 16
  • 168
  • 197
  • There can be only one.... answer. But take solace in the fact that when multiple minds arrive independently at the same conclusion; it's lends credit to it's accuracy. – Kulingar May 15 '13 at 20:03
1

jQuery each() is most likely the answer you are looking for.

var theImageOrder = "";
$('#sortable > li > img').each(function(index, element){
    theImageOrder += element.attr('src').howeverYouWantToModifyThisString();
});
km6zla
  • 4,787
  • 2
  • 29
  • 51
1

I put together a vanilla JS recursive example in ES6 that may help future onlookers:

let images = [];

const processChildrenNodes = (node, getNodeChildren) => {
  const nodeChildren = [...node.childNodes];

  for (const thisNode of nodeChildren) {
    if (getNodeChildren)
      processChildrenNodes(thisNode, true);

    if (thisNode.nodeName === 'IMG') {
      images.push(
        thisNode.getAttribute('src')
        .replace('.jpg', '')
        .split('/')
        .filter(item => item !== 'images')
      );
    }
  }
};

processChildrenNodes(document.getElementById('sortable'), true);

This will allow for you to look through all nodes children for an IMG, and then parse the images into an "images" array. This could be compacted even more using reduce, but I figured this would give you an easy option without Jquery.

The example above was tested on JSFIDDLE

Ron
  • 151
  • 2