Error using Javascript removeChild function

Asked

Viewed 1,088 times

1

I am using javascript to make a label and an input type text appear after selecting one of the radioButtons of my code, which in case are two, and if one is selected, the other automatically disappears.

The code is working perfectly, the problem is that an error appears in the browser console that is giving me a toc, and if it is appearing it is because it may generate a problem in the future...

Error: index.html:44 Uncaught Domexception: Failed to execute 'removeChild' on 'Node': The Node to be Removed is not a Child of this Node. At Htmlinputelement.cpf_option.onclick

Source code:

    <!DOCTYPE html>
<html lang="pt-br">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <div id="DivPrincipal">
        <label>CPF</label>
        <input type="radio" name="cpf_cnpj_options" value="CPF" id="cpf_options">
        <label>CNPJ</label>
        <input type="radio" name="cpf_cnpj_options" value="CNPJ" id="cnpj_options">       
    </div>


    <script>       
        var radionButtons = document.getElementsByName("cpf_cnpj_options")
        var cpf_option = document.querySelector("#cpf_options");
        var cnpj_option = document.querySelector("#cnpj_options");

        var label_cpf = document.createElement("label");
        label_cpf.innerHTML = "CPF";
        var input_cpf = document.createElement("input");
        var attrPlaceHolderCpf = document.createAttribute("placeholder");
        attrPlaceHolderCpf.value = "CPF";
        input_cpf.setAttributeNode(attrPlaceHolderCpf);

        var label_cnpj = document.createElement("label");
        label_cnpj.innerHTML = "CNPJ";
        var input_cnpj = document.createElement("input");
        var attrPleaceHolder = document.createAttribute("placeholder");
        attrPleaceHolder.value = "CNPJ";
        input_cnpj.setAttributeNode(attrPleaceHolder);

        cpf_option.onclick = function () {
            for (let index = 0; index < radionButtons.length; index++) {
                if (radionButtons[index] ==  cpf_option) {
                    document.getElementById("DivPrincipal").appendChild(label_cpf)
                    document.getElementById("DivPrincipal").appendChild(input_cpf)
                }           
            }            
            document.getElementById("DivPrincipal").removeChild(label_cnpj)
            document.getElementById("DivPrincipal").removeChild(input_cnpj)              
        }

        cnpj_option.onclick = function () {
            for (let index = 0; index < radionButtons.length; index++) {
                if (radionButtons[index] == cnpj_option) {
                    document.getElementById("DivPrincipal").appendChild(label_cnpj)
                    document.getElementById("DivPrincipal").appendChild(input_cnpj)
                }                
            }            
            document.getElementById("DivPrincipal").removeChild(label_cpf)
            document.getElementById("DivPrincipal").removeChild(input_cpf)                
        }

    </script>
</body>
</html>

1 answer

3


It is occurring that at the time of using the removeChild, the element created is not yet a child of div#DivPrincipal, that is, it was only created, but not yet placed in the div.

For example, when clicking the first time on CNPJ radio, the label and input referring to CPF were created, but do not exist in the div, and vice versa.

What should be done is to check if the elements exist in the div before trying to remove them. You can just check if the label exists by using .closest(), in two parts of the code:

Here, referring to the CNPJ:

if(label_cnpj.closest("#DivPrincipal")){        
   document.getElementById("DivPrincipal").removeChild(label_cnpj)
   document.getElementById("DivPrincipal").removeChild(input_cnpj)              
}

And here, referring to the CPF:

if(label_cpf.closest("#DivPrincipal")){
   document.getElementById("DivPrincipal").removeChild(label_cpf)
   document.getElementById("DivPrincipal").removeChild(input_cpf)                
}

IE11 compatibility

Like the métoto .closest() does not have support in IE11, you can use .querySelectorAll() with .length (or else use this polyfill). This will count how many selector elements there are in the div, and if there is at least 1, you will enter the if:

On the CNPJ:

if(document.getElementById("DivPrincipal").querySelectorAll("input[placeholder='CNPJ']").length){
   document.getElementById("DivPrincipal").removeChild(label_cnpj)
   document.getElementById("DivPrincipal").removeChild(input_cnpj)              
}

At the CPF:

if(document.getElementById("DivPrincipal").querySelectorAll("input[placeholder='CPF']").length){
   document.getElementById("DivPrincipal").removeChild(label_cpf)
   document.getElementById("DivPrincipal").removeChild(input_cpf)                
}

Remembering that on the dial "input[placeholder='CPF']" must be exactly the same placeholder of the respective field.

Suggestion

You can still reduce and improve the caching reading to document.getElementById("DivPrincipal") in a variable:

var divprincipal = document.getElementById("DivPrincipal");

With that you don’t have to repeat document.getElementById("DivPrincipal") several times.

Example:

var radionButtons = document.getElementsByName("cpf_cnpj_options")
var cpf_option = document.querySelector("#cpf_options");
var cnpj_option = document.querySelector("#cnpj_options");

var label_cpf = document.createElement("label");
label_cpf.innerHTML = "CPF";
var input_cpf = document.createElement("input");
var attrPlaceHolderCpf = document.createAttribute("placeholder");
attrPlaceHolderCpf.value = "CPF";
input_cpf.setAttributeNode(attrPlaceHolderCpf);

var label_cnpj = document.createElement("label");
label_cnpj.innerHTML = "CNPJ";
var input_cnpj = document.createElement("input");
var attrPleaceHolder = document.createAttribute("placeholder");
attrPleaceHolder.value = "CNPJ";
input_cnpj.setAttributeNode(attrPleaceHolder);


var divprincipal = document.getElementById("DivPrincipal");
cpf_option.onclick = function () {
   for (let index = 0; index < radionButtons.length; index++) {
       if (radionButtons[index] ==  cpf_option) {
           divprincipal.appendChild(label_cpf)
           divprincipal.appendChild(input_cpf)
       }           
   }    
   if(divprincipal.querySelectorAll("input[placeholder='CNPJ']").length){
      divprincipal.removeChild(label_cnpj)
      divprincipal.removeChild(input_cnpj)              
   }
}

cnpj_option.onclick = function () {
   for (let index = 0; index < radionButtons.length; index++) {
       if (radionButtons[index] == cnpj_option) {
           divprincipal.appendChild(label_cnpj)
           divprincipal.appendChild(input_cnpj)
       }                
   }
   if(divprincipal.querySelectorAll("input[placeholder='CPF']").length){
      divprincipal.removeChild(label_cpf)
      divprincipal.removeChild(input_cpf)                
   }
}
<div id="DivPrincipal">
  <label>CPF</label>
  <input type="radio" name="cpf_cnpj_options" value="CPF" id="cpf_options">
  <label>CNPJ</label>
  <input type="radio" name="cpf_cnpj_options" value="CNPJ" id="cnpj_options">       
</div>

Using Try to catch...

Another way is by ignoring the mistake with Try.. catch. The block try{} will attempt to execute the code, and in case of error, no error warning will be displayed. The block catch(e){} returns the error in the argument e, but you will only use the block catch if you want to treat the error, which does not seem to be the case. It would look like this:

On the CNPJ:

try{
   divprincipal.removeChild(label_cnpj)
   divprincipal.removeChild(input_cnpj)              
}catch(e){}

At the CPF:

try{
   divprincipal.removeChild(label_cpf)
   divprincipal.removeChild(input_cpf)                
}catch(e){}
  • 1

    I wasn’t getting the divPrincipal element, but now it worked. And by the way, your reply was very thorough, helped me understand more about how JS works in relation to HTML.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.