Reputation: 986
I noticed this strange behaviour with my jQuery code, when it pulled a JSON from an AJAX request to create the elements with a template. What I am trying to do is, with the JSON, which is technically an array of few objects, I am constructing a series of cards, which show something to the user.
I have drilled down the problem to the below code (without using AJAX) and got the issue replicated here as well.
$(function() {
// Mimicking the AJAX Request.
// The getJSON gets an array of objects.
// I am limiting it to just string array, and lenght of 3 to keep things simple.
var response = ["Alice", "Bob", "Charlie"];
// My Code.
$.each(response, function(index, value) {
$tmp = $(".template").clone();
$tmp.find("strong").text("Name");
$tmp.find("span").text(value);
$tmp.appendTo("body");
});
});
* {
margin: 0;
padding: 0;
list-style: none;
text-align: center;
}
.template {
border: 1px solid #ccc;
border-radius: 5px;
padding: 5px;
width: 150px;
line-height: 150px;
display: inline-block;
cursor: pointer;
margin: 5px;
}
<script src="https://code.jquery.com/jquery-2.1.4.js"></script>
<div class="template">
<strong>All</strong>
<span>Names</span>
</div>
Problem
If you see in the above snippet, you could find that the elements are exponentially increasing. i.e., for the nth element, it displays the cards for n times, starting from one:
n card desc
--- ---------- -----------------------------------
1 1 card Alice is displayed only once.
2 2 cards Bob is displayed two times.
3 4 cards Charlie is displayed four times.
And so on... I could find an amusing series here, which resembles the powers of 2: 1, 2, 4, 8, 16...
(20, 21, 22, 23, 24,... Exponential on 2).
Another strange behaviour that I noticed was, when I use an extra <div>
, this problem doesn't happen. For e.g., consider the same code, but wrap the template by nesting it into another <div>
structure:
$(function() {
// Mimicking the AJAX Request.
// The getJSON gets an array of objects.
// I am limiting it to just string array, and lenght of 3 to keep things simple.
var response = ["Alice", "Bob", "Charlie"];
// My Code.
$.each(response, function(index, value) {
$tmp = $(".extra .template").clone();
$tmp.find("strong").text("Name");
$tmp.find("span").text(value);
$tmp.appendTo("body");
});
});
* {
margin: 0;
padding: 0;
list-style: none;
text-align: center;
}
.template {
border: 1px solid #ccc;
border-radius: 5px;
padding: 5px;
width: 150px;
line-height: 150px;
display: inline-block;
cursor: pointer;
margin: 5px;
}
<script src="https://code.jquery.com/jquery-2.1.4.js"></script>
<div class="extra">
<div class="template">
<strong>All</strong>
<span>Names</span>
</div>
</div>
I am not sure what exactly is causing the problem here. Is there any crazy mistake that I am doing? :)
Upvotes: 2
Views: 78
Reputation: 167192
The reason is, you are not removing the class template
, so every time you append, you have double the number of elements with the class template
, so the first way to do is, when you do the clone, you need to remove the class template
.
$tmp = $(".template").clone().removeClass("template");
Note: In the below preview I have slightly modified the class, because of styling.
$(function() {
// Mimicking the AJAX Request.
// The getJSON gets an array of objects.
// I am limiting it to just string array, and lenght of 3 to keep things simple.
var response = ["Alice", "Bob", "Charlie"];
// My Code.
$.each(response, function(index, value) {
// ----------- Change here ---------- //
$tmp = $(".template").clone().removeClass("template");
$tmp.find("strong").text("Name");
$tmp.find("span").text(value);
$tmp.appendTo("body");
});
});
* {
margin: 0;
padding: 0;
list-style: none;
text-align: center;
}
.item {
border: 1px solid #ccc;
border-radius: 5px;
padding: 5px;
width: 150px;
line-height: 150px;
display: inline-block;
cursor: pointer;
margin: 5px;
}
<script src="https://code.jquery.com/jquery-2.1.4.js"></script>
<div class="item template">
<strong>All</strong>
<span>Names</span>
</div>
The reason why, second time it worked is, you had enclosed the template inside the extra
div, and you are appending the new .template
s to the <body>
directly, so the selector .extra .template
selects only one. Still this is a mistake because each and every <div>
you generate bears the template
class, which ideally shouldn't.
Hope the explanation is clear.
Upvotes: 2