SitePoint Sponsor

User Tag List

Results 1 to 14 of 14
  1. #1
    SitePoint Member
    Join Date
    Jun 2014
    Posts
    6
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Iteration in vanilla JS

    Hello everyone,

    I've been trying to figure this out for a while now, but can't get a decent result.
    I hope someone can explain how I can achieve this.

    Let's take this jQuery example:
    Code:
    $("a[href$='.pdf']").prepend('<img src="images/pdf.png" alt="" />');
    Now I would like to achieve the same result in vanilla JS. This is what I came up with, but as a JS newbie... I'm stuck:
    Code:
    function prepender(el, source, alt) {
    	var anchor = document.querySelectorAll(el);
    	var newElement = document.createElement("img");
    	      newElement.src = source;
    	      newElement.alt = alt;
    
    	for (var i = 0; i < anchor.length; i++) {
    		var arr = [];
    		arr.push(anchor[i]);
    		var parent = anchor[i].parentNode;
    		parent.insertBefore(newElement, anchor[i]);
    	}
    }
    prepender("a[href$='.pdf']", "images/pdf.png", "PDF link");
    Why am I only getting the last iteration?

  2. #2
    SitePoint Addict bronze trophy WolfShade's Avatar
    Join Date
    Mar 2014
    Location
    St. Louis, MO, USA
    Posts
    334
    Mentioned
    9 Post(s)
    Tagged
    0 Thread(s)
    I could be wrong, but it looks like you're declaring arr as a blank array on each iteration. Move it to before the for loop.. maybe that will fix it.

    HTH,

    ^_^

  3. #3
    SitePoint Member
    Join Date
    Jun 2014
    Posts
    6
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks for the effort WolfShade,
    but moving the empty array up didn't help:

    Code:
    function prepender(el, source, alt) {
    	var anchor = document.querySelectorAll(el);
    	var newElement = document.createElement("img");
    	      newElement.src = source;
    	      newElement.alt = alt;
    
    	var arr = [];
    
    	for (var i = 0; i < anchor.length; i++) {
    		arr.push(anchor[i]);
    		var parent = anchor[i].parentNode;
    		parent.insertBefore(newElement, anchor[i]);
    	}
    }
    prepender("a[href$='.pdf']", "images/pdf.png", "PDF link");

  4. #4
    SitePoint Addict bronze trophy WolfShade's Avatar
    Join Date
    Mar 2014
    Location
    St. Louis, MO, USA
    Posts
    334
    Mentioned
    9 Post(s)
    Tagged
    0 Thread(s)
    Somewhere in there, alert the length of anchor, just to make sure you're getting more than the last one.

    Curious: what is the purpose of the array? Why push data into it, but then use anchor[i] as the parent insert?

    ^_^

  5. #5
    SitePoint Zealot
    Join Date
    Aug 2011
    Location
    Amsterdam, The Netherlands
    Posts
    168
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    push is a command with which you can add an item to an existing array. In your case, a normal iteration should do:

    Code:
    function prepender(el, source, alt) {
        var anchor = document.querySelectorAll(el);
        var newElement = document.createElement("img");
            newElement.src = source;
            newElement.alt = alt;
    
        for (var i=0; i< anchor.length; i++) {
            var parent = anchor[i].parentNode;
            parent.insertBefore(newElement, anchor[i]);
        }
    }
    prepender("a[href$='.pdf']", "images/pdf.png", "PDF link");

  6. #6
    SitePoint Addict bronze trophy WolfShade's Avatar
    Join Date
    Mar 2014
    Location
    St. Louis, MO, USA
    Posts
    334
    Mentioned
    9 Post(s)
    Tagged
    0 Thread(s)
    Also.. didn't think of it, until now. Do all the PDF filenames end in ".pdf"? Or are there any that end in ".PDF"?

  7. #7
    SitePoint Member
    Join Date
    Jun 2014
    Posts
    6
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    @Wolfshade,

    I thought that I had to push/collect all the anchor tags containing the specified condition (in this case all anchor tags that have an attribute of src that ends with '.pdf') in an empty array myself in order to work with them... but apparently not. Seems like the querySelectorAll() & for loop already take care of that if I'm understanding that correctly?

    And the jQuery result will show two prepended PDF icons.

    @Frank S,

    Sure, please see attachment. Thanks for the effort!
    iteration_test.zip

  8. #8
    SitePoint Member
    Join Date
    Jun 2014
    Posts
    6
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by WolfShade View Post
    Somewhere in there, alert the length of anchor, just to make sure you're getting more than the last one.

    ...

    ^_^
    I will get two results if I do a

    Code:
    console.log(anchor);
    and that's correct, so how and why is it skipping to the last result?

  9. #9
    SitePoint Addict bronze trophy WolfShade's Avatar
    Join Date
    Mar 2014
    Location
    St. Louis, MO, USA
    Posts
    334
    Mentioned
    9 Post(s)
    Tagged
    0 Thread(s)
    According to MDN, querySelectorAll() returns a list (not an array, as I mistakenly assumed) of all matching selectors. Maybe pushing the list into an array then looping the array?

    HTH,

    ^_^

  10. #10
    Gre aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    6,079
    Mentioned
    219 Post(s)
    Tagged
    12 Thread(s)
    Hi,

    Are you trying to write this function as an exercise?
    If not, you can use:
    Code:
    parent.insertBefore(el, parent.firstChild);

  11. #11
    SitePoint Member
    Join Date
    Jun 2014
    Posts
    6
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi Pullo,

    Yes it's an exercise. It's more important for me to know how and why something is done the way it's done in pure/modern JS.

  12. #12
    SitePoint Addict bronze trophy WolfShade's Avatar
    Join Date
    Mar 2014
    Location
    St. Louis, MO, USA
    Posts
    334
    Mentioned
    9 Post(s)
    Tagged
    0 Thread(s)
    anchor.split(',') should turn the list into an array without looping. Then you can loop the array and insertBefore().

    ^_^

  13. #13
    Gre aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    6,079
    Mentioned
    219 Post(s)
    Tagged
    12 Thread(s)
    Hi,

    You can do it like this:

    Code:
    function prepender(el, source, alt) {
    	var anchor = document.querySelectorAll(el);
    
    	for (var i = 0; i < anchor.length; i++) {
    	  var newElement = document.createElement("img");
    	  newElement.src = source;
    	  newElement.alt = alt;
    	  
              var parent = anchor[i].parentNode;
    	  parent.insertBefore(newElement, anchor[i].previousSibling);
    	}
    }
    prepender("a[href$='.pdf']", "images/pdf.png", "PDF link");
    The main difference being that the image creation has been moved into the for loop and you are inserting the new element not before the anchor tag, but before the anchor tag's previous sibling.

    A shorter way to do it would be:

    Code:
    var elems = document.querySelectorAll("a[href$='.pdf']");
    
    [].forEach.call(elems, function(el, i) {
      var image = document.createElement("img");
      image.src = "https://d0.awsstatic.com/icons/file-icon-pdf-25x25.png";
      el.parentNode.insertBefore(image, el.previousSibling);
    });
    Demo

    You might also want to read: http://toddmotto.com/a-comprehensive...nding-the-dom/

  14. #14
    SitePoint Member
    Join Date
    Jun 2014
    Posts
    6
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    @ Pullo,
    I see..moving newElement into the for loop.

    Thank you for helping me understand iteration in JS a little bit better and also thanks for the interesting resource.
    Also thanks for showing me a shorter way with forEach! Very interesting and much appreciated. Keeps me motivated to do more with JS.

    Cheers!
    John


Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •