简体   繁体   中英

classList.toggle() not working after cloning in JavaScript

I have the following div:

<div id="template">

    <label><h1>Enter your title</h1></label>
    <input type="text" name="title[]" placeholder="Enter your title">
    <label><p>Enter your text</p></label>
    <textarea type="text" name="textbox1[]" placeholder="Enter your text"></textarea>

</div>

I clone this div and append it using JavaScript. On click on a button, the div is supposed to open by toggling the .open class.

Relevant JavaScript:

function addClonedDiv() {

    var div = document.getElementById('template');
    window.clonedDiv = div.cloneNode(true);
    document.getElementById('otherDiv').appendChild(clonedDiv);
    clonedDiv.firstChild.className = "newDiv";
}

function addIframe() {

    clonedDiv.firstChild.classList.toggle("open");

}

(There's two buttons, one clones the div and the other one shows it, it's hidden by default, otherDiv is the div I want to append the new div to. I add the class="newDiv" to it because I will need it later for other purposes which are not relevant to this question, however, I wanted to include it as I don't know if that may be the problem). The .open class in CSS:

.open {
    visibility: visible;
    width: 100%;
}

However, when I click on the button that is supposed to show the div, I get this error message in the console: Cannot read property 'toggle' of undefined. I'm not sure why the new div would be undefined and how to fix that.

I read through other questions on here that said that I have to deep clone the div, which I tried applying (as you can see), but I still received the same error message. I know cloning doesn't clone event-handlers, but I'm pretty sure, that that is not the problem in my case.

I did read through plenty of other questions and did my research, however, I could not fix the problem. I definitely want to solve this problem in JavaScript and not jQuery.

A few problems here (and even more in your fiddle, but since you seem to have gotten until the error message you quoted, I'll fix the ones of the fiddle for free).

Error repro:

 function addClonedDiv() { var div = document.getElementById('template'); window.clonedDiv = div.cloneNode(true); document.getElementById('otherDiv').appendChild(clonedDiv); clonedDiv.firstChild.className = "newDiv"; }; // open is reserved function open_() { console.log(clonedDiv); clonedDiv.firstChild.classList.toggle("open"); }; 
 #template { visibility: hidden; } .newDiv.open { visibility: visible; } 
 <div id="otherDiv"> <button onclick="addClonedDiv()"> Add Item </button> <button onclick="open_()"> Open </button> </div> <div id="template"> <label><h1>Enter your title</h1></label> <input type="text" name="title[]" placeholder="Enter your title"> <label><p>Enter your text</p></label> <textarea type="text" name="textbox1[]" placeholder="Enter your text"></textarea> </div> 


So let's first fix the error message:

clonedDiv.firstChild is a Node, and even a textNode, representing a new line character. So you can set a property to it, but it doesn't inherit from Element nor from HTMLElement prototypes and thus doesn't have a classList property.

What you want is clonedDiv.firstElementChild (in addCloneDiv too).

Then, Node.cloneNode will copy all the attributes of an Element, when called on an Element. So your clonedDiv will also have the id="template" attribute. This means that your .newDiv.open rule will have less importance than the #template one.

 function addClonedDiv() { var div = document.getElementById('template'); window.clonedDiv = div.cloneNode(true); document.getElementById('otherDiv').appendChild(clonedDiv); clonedDiv.firstElementChild.className = "newDiv"; // grab the first Element clonedDiv.removeAttribute('id'); // ids must be unique per document }; function open_() { clonedDiv.firstElementChild.classList.toggle("open"); }; 
 #template, .newDiv { visibility: hidden; } .newDiv.open { visibility: visible; } 
 <div id="otherDiv"> <button onclick="addClonedDiv()"> Add Item </button> <button onclick="open_()"> Open </button> </div> <div id="template"> <label><h1>Enter your title</h1></label> <input type="text" name="title[]" placeholder="Enter your title"> <label><p>Enter your text</p></label> <textarea type="text" name="textbox1[]" placeholder="Enter your text"></textarea> </div> 

Now I'm not sure this is really what you wanted to occur, but I'll let you find yourself.

try this:

 var clonedDiv; function clone(){ clonedDiv = document.getElementById('template').cloneNode(true); document.getElementById('otherDiv').appendChild(clonedDiv); clonedDiv.className = "newDiv"; } function show(){ (!clonedDiv.classList.contains("open")) ? clonedDiv.classList.add("open"):clonedDiv.classList.remove("open"); } 
 .newDiv{ visibility: hidden; } .open { visibility: visible; width: 100%; } 
 <div id="template"> <label><h1>Enter your title</h1></label> <input type="text" name="title[]" placeholder="Enter your title"> <label><p>Enter your text</p></label> <textarea type="text" name="textbox1[]" placeholder="Enter your text"></textarea> <button onclick="clone()">clone</button> <button onclick="show()">show</button> </div> <div id="otherDiv"> </div> 

instead of toggle

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM