Skip to content Skip to sidebar Skip to footer

Iterate Through Elements With The Same Class And Remove Them

I'm building an app and I need to remove all link elements with a specific class from the header. I've built an example of the problem I'm having in the w3schools editor. For the p

Solution 1:

The problem is that getElementsByClassName returns a live HTMLCollection - if you remove an element from it during an iteration, the collection will change when you remove it. For example:

const foos = document.getElementsByClassName('foo');
console.log(foos[1].textContent);
foos[0].remove();
console.log(foos[1].textContent);
<div class="foo">a</div>
<div class="foo">b</div>
<div class="foo">c</div>

It's quite unintuitive. Either iterate backwards through the collection (eg, from length - 1, to length - 2, ... 0), to ensure every element gets iterated over, or use querySelectorAll instead, which returns a static NodeList:

const links = head.querySelectorAll('.link-to-remove');

Another benefit to querySelectorAll is that newer browsers support forEach on NodeLists, so you can iterate over them directly, rather than having to use an ugly for loop:

document.querySelectorAll('head .link-to-remove').forEach((removeMe) => {
  removeMe.remove();
});

(as you can see, there's no need to select the head if you put the head in the query string passed to querySelectorAll - you may also remove() an element directly, rather than having to reference its parent and use removeChild)


Solution 2:

The getElementsByTagName method returns a live HTML element collection when you removed an element from DOM it will get updated so it will skip some elements since the index of the element is changing.

To make it works to use a variable which holds the length of collection and iterate backward.

function removeLinks() {
  const head = document.getElementsByTagName('head')[0];
        const links = head.getElementsByClassName('link-to-remove');
        let i = links.length;
        while(i--) {
            head.removeChild(links[i]);
        }
}

Or alternately, you can use forEach as well

function removeLinks() {
  const head = document.getElementsByTagName('head')[0];
  const links = head.getElementsByClassName('link-to-remove');
  links.forEach(el => el.remove())     
}

Much simpler one using querySelectorAll, forEach and remove methods.

function removeLinks() {
  document.querySelectorAll('head .link-to-remove').forEach(el => el.remove())     
}

Solution 3:

you have to set the stylesheet to be disabled as it keeps the css styles in memory so removing the element will not work, it can also cause it to crash in some instances if I remember correctly.

function removeLinks() {
  const head = document.getElementsByTagName('head')[0];
        const links = head.getElementsByClassName('link-to-remove');
        for(let i = 0; i < links.length; i++) {
            links[i].disabled = true;
        }
}

Eg:document.styleSheets[0].disabled = true;

Jquery way => $('link[title=mystyle]')[0].disabled=true;


Solution 4:

<link>s can be removed like any other tag. The older methods like .getElementsByClassName(), .getElementsByTagName(), and .getElementsByName() are Live HTMLCollections (an array-like object) so the .length is updated every iteration and it diminishes and prematurely ends the loops. You can achieve your objective by disabling each <link> instead of removing them (.length isn't touched.) or use a collection method that returns a static NodeList (an array-like object) like the more versatile .querySelectorAll() method. Another way is to convert an array-like object into an array by Array.from() This demo:

  • shows two different interfaces to handle <link>

    • First one uses the styleSheet Object of the CSSStyleSheet interface

      • Click the yellow button to disable the targeted <link>s
    • Second HTMLLinkElement interface of the DOM using .querySelectorAll()

      • Click the red button to to remove the targeted <link>s

      • Note: A Live HTMLCollection was made so an accurate count could be made of the link.link-to-remove in the console when the they are removed.

To properly test each example, rerun the demo and then click the other button.

<!DOCTYPE html>
<html>

<head>
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" class="link-to-remove">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" class="link-to-remove">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" class="link-to-remove">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" class="link-to-remove">
</head>

<body>
  <button class='btn btn-warning'>CLICK TO DISABLE ALL STYLESHEETS</button>
  <a href='#/' class='btn btn-danger'>REMOVE ALL <code>link.link-to-remove</code></a>

  <script>
    // Collect all stylesheets and convert to an array
    let sheets = Array.from(document.styleSheets);

    console.log('=========STYLESHEET QTY===========');

    // Test: Check how many stylesheets there are
    console.log('This page has ' + sheets.length + ' stylesheets');

    console.log('=============All HREF=============');

    // Test: View each stylesheet href
    for (let sheet of sheets) {
      console.log(sheet.href);
    }

    document.querySelector('button').onclick = function(e) {
      // Start disabling all stylesheets beginning at the 3rd position 
      for (let s = 0; s < sheets.length; s++) {
        if (s >= 2) {
          sheets[s].disabled = true;
        }
      }

      console.log('=============DISABLED=============');

      // Test: See which stylesheets were disabled
      for (let sheet of sheets) {
        console.log(sheet.disabled);
      }
    }

    let nodeList = document.querySelectorAll('.link-to-remove');
    let htmlCol = document.getElementsByClassName('link-to-remove');

    document.querySelector('a').onclick = function(e) {
      nodeList.forEach(link => link.remove());

      console.log('=========STYLESHEET QTY===========');

      // Test: Check how many stylesheets there are
      console.log('This page has ' + htmlCol.length + ' stylesheets with the className: .link-to-remove');

      console.log('=============All CLASS=============');

      // Test: View each all link.class

      for (let tag of htmlCol) {
        console.log(tag.className);
      }
    }
  </script>
</body>

</html>

Post a Comment for "Iterate Through Elements With The Same Class And Remove Them"