2

I have a function that appends a "div" child into a parent node, then I need to delete this child using the removeChild() method, but it doesn't work.

This is my code:

function ColorCards()
        {for (i=0; i<numerocaselle; i++)
            {document.getElementsByClassName("MemoryCards")[i].style.border="none"
            var esempiocolore=document.createElement('div')
            esempiocolore.style="position: relative; height: 80px; width: 130px; background-image: url('img/backcard"+cartaesempio+".png'); background-size: cover;"
            document.getElementsByClassName("MemoryCards")[i].appendChild(esempiocolore)
            }
        }

        function CleanColorCards()
        {for (i=0; i<numerocaselle; i++)
            {document.getElementsByClassName("MemoryCards")[i].style.border="dashed 3px #02A494"
            document.getElementsByClassName("MemoryCards")[i].removeChild(document.getElementsByTagName("div"))
            }
        }

Does somebody have any suggestion on how to make it work?

juancito
  • 866
  • 2
  • 9
  • 22

4 Answers4

0

You are passing an NodeList to removeChild, while you should pass a single node. Secondly, document.getElementsByTagName("div") is going to also find elements that are not children of the parent you are trying to remove a child from.

So do it like this:

// Avoid repetition of code, and store the result in a variable:
var nodelist = document.getElementsByClassName("MemoryCards");
for (var i=0; i<numerocaselle; i++){
    const parent = nodelist[i];
    parent.style.border="dashed 3px #02A494";
    // Perform `getElementsByTagName` on the parent node only, and take first match:
    parent.removeChild(parent.getElementsByTagName("div")[0]);
}

Note that querySelector is designed for getting one node-result, so that last line can read:

    parent.removeChild(parent.querySelector("div"));
trincot
  • 317,000
  • 35
  • 244
  • 286
  • Why in the world do people believe that scanning the DOM for all matches, making a node list and then throwing that node list away just to use the first match is a good idea?[Just use `.querySelector()`](https://stackoverflow.com/questions/54952088/how-to-modify-style-to-html-elements-styled-externally-with-css-using-js/54952474#54952474). – Scott Marcus May 05 '19 at 20:14
  • @ScottMarcus, Sure, `querySelector` avoids creating a node list (added to answer). It is likely from the OP's code, that there is only one child `div` anyway, so the gain (relative to the cost of accessing the DOM) will be very limited. – trincot May 05 '19 at 20:57
  • It doesn't matter how many matches there are, it matters how big and deep the DOM is, so if you are scanning the entire DOM for just the first matching element, the extra work could be much more than limited. – Scott Marcus May 05 '19 at 21:11
  • That is true for the OP's code, which did not work anyway. But in my answer only the parent node is searched which suppsedly only has one child. – trincot May 05 '19 at 21:41
  • But, if the parent node will be completely searched. `.getElementsByTagName()` isn't going to stop at the first match. If the parent node is deep, you've got the same problem. – Scott Marcus May 05 '19 at 21:50
0

Just a couple notes:

  1. Using a for loop is unnecessary. Having a variable to hold the count of the length of .MemoryCards will leave room for errors. Instead, I recommend an Array function such as .forEach() to iterate through your elements.
  2. The bulk of your element styles should be handled with classes in CSS. By doing this your function will be more concise and easier to manage.
  3. And, to answer your question:
    1. To remove all child nodes for each .MemoryCards, I would recommend using a loop and the node.removeChild() method as it will perform faster than setting node.innerHTML=''.
    2. See the comments in this post as why this method would be best.

let cartaesempio = 10;
ColorCards = () =>
  Array.from(document.getElementsByClassName("MemoryCards"))
  .forEach(e => {
    e.classList.add('borderNone');
    let esempiocolore = document.createElement('div');
    esempiocolore.style.backgroundImage = `url('https://cdn.dribbble.com/users/285803/screenshots/1066705/dribbble.gif')`;
    e.appendChild(esempiocolore);
  });

CleanColorCards = () =>
  Array.from(document.getElementsByClassName("MemoryCards"))
  .forEach(e => {
    e.classList.add('boderDashed');
    while (e.firstChild) {
      e.removeChild(e.firstChild);
    }
  });

ColorCards();
CleanColorCards();
/* Children of the .MemoryCards nodes */

.MemoryCards div {
  position: relative;
  height: 80px;
  width: 130px;
  background-size: cover;
}

.borderNone {
  border: none;
}

.boderDashed {
  border: dashed 3px #02A494;
}
<div class='MemoryCards'></div>

Hope this helps,

Miroslav Glamuzina
  • 4,472
  • 2
  • 19
  • 33
-1

just check your error ! document.getElementsByTagName("div") return an array of div that's basic js meaning you've to search more by ourself. Use a manual, like the one at w3schools or a book whatever :-)

jean3xw
  • 121
  • 7
-1

You are passing removeChild all the divs in the document. Try replacing this line:

document.getElementsByClassName("MemoryCards")[i].removeChild(document.getElementsByTagName("div"))

With:

var memoryCardsEl = document.getElementsByClassName("MemoryCards")[i];
memoryCardsEl.removeChild(memoryCardsEl.getElementsByTagName("div")[0]);
benkol
  • 351
  • 1
  • 13