Why appending a div using html and jquery variable has different outputs? - javascript

Trying to solve a practice related to javaScript and JQuery, and have met an issue which I could not identify.
I created a variable to store a div, and tried to create multiple instances of it as follows:
(there is a logical mistake I have in inner loop related to the number of appended defineBox objects but this is something I am
working on separately,not related to this topic)
$("#wrapper").empty();
var lineBox=document.createElement('div');
for(var i=0; i<size; i++){
$('#wrapper').append('lineBox');
for(var j=0; j<size; j++){
$("#wrapper > div ").append(defineBox(boxSize));
}
}
When the code is executed, it shows only one "lineBox" div in html document. defineBox is appended to the lineBox div.
When I use the following code instead, it displays "i" times of 'div' just as expected from the loop and each 'div' includes 'defineBox's.
for(var i=0; i<size; i++){
$('#wrapper').append('<div></div>');
for(var j=0; j<size; j++){
$("#wrapper > div ").append(defineBox(boxSize));
}
}
I thought creating a var with document.createElement('div') would have the same result as '<div></div>'. Where does the difference come from?

Try the jQuery's .clone() method. You're creating one instanced of the div in the dom.
$("#wrapper").empty();
var lineBox=document.createElement('div');
$('#wrapper').append(lineBox);
for(var i=0; i<size-1; i++){
$('#wrapper').append(lineBox.clone());
for(var j=0; j<size; j++){
$("#wrapper > div ").append(defineBox(boxSize));
}
}
Here is the documentation for the clone method of jQuery:
https://api.jquery.com/clone/

Each time this expression called
$('#wrapper').append('<div></div>');
jQuery creates a new div element. In the first example you've shared, new div element created just once with var lineBox=document.createElement('div');

Related

Animating a swap of cells in a table on click using JQuery

I'm trying to make a simple flash-card game in JavaScript using JQuery. In one part of the game, you should click on a row in a "table" (tablica) made out of divs (tablica[i][j]) to swap the cells in that row (to put the content in the cell in the correct column). Here is the relevant piece of code:
for (var j=0; j<odgovor1.length; j++)
for (var i=1; i<3; i++)
{
tablica[i][j]=document.createElement("div");
tablica[i][j].setAttribute("class","rijecUDrugomDijelu");
if (i===1) tablica[i][j].appendChild(document.createTextNode(odgovor1[j]));
else if (i===2) tablica[i][j].appendChild(document.createTextNode(odgovor2[j]));
tablica[i][j].style.top=228+27*j;
tablica[i][j].style.left=-153+110+153*i;
tablica[i][j].onclick=eval(
"(function()"+
"{"+
"var tmp=tablica[1]["+j+"].style.left;"+
"tablica[1]["+j+"].style.left=tablica[2]["+j+"].style.left;"+
"tablica[2]["+j+"].style.left=tmp;"+
"tmp=odgovor1["+j+"];"+
"odgovor1["+j+"]=odgovor2["+j+"];"+
"odgovor2["+j+"]=tmp;"+
"})"
);
pozadina.appendChild(tablica[i][j]);
}
When the user clicks on a row in that table, the cells in that row are swapped, and the content of the table is correctly tracked in the string arrays odgovor1 and odgovor2. However, they are swapped without any animation, they are swapped immediately. When I try to apply JQuery animations to the cells (divs) tablica[1][j] and tablica[2][j], the program crashes. Do you know how to do that properly?Again, I assure you, the code above works well now, but when I try to use JQuery animations instead of simply swapping the properties style.left, it crashes.
Using object properties instead of eval appears to work:
for (var j=0; j<odgovor1.length; j++)
for (var i=1; i<3; i++)
{
tablica[i][j]=document.createElement("div");
tablica[i][j].setAttribute("class","rijecUDrugomDijelu");
if (i===1) tablica[i][j].appendChild(document.createTextNode(odgovor1[j]));
else if (i===2) tablica[i][j].appendChild(document.createTextNode(odgovor2[j]));
tablica[i][j].style.top=228+27*j;
tablica[i][j].style.left=-153+110+153*i;
tablica[i][j].redak=j;
tablica[i][j].onclick=
function()
{
var tmp=tablica[1][this.redak].style.left;
$(tablica[1][this.redak]).animate({left:(tablica[2][this.redak].style.left)},500);
$(tablica[2][this.redak]).animate({left:(tmp)},500);
tmp=odgovor1[this.redak];
odgovor1[this.redak]=odgovor2[this.redak];
odgovor2[this.redak]=tmp;
}
pozadina.appendChild(tablica[i][j]);
}

Append items in a for loop- jquery

I am adding a simple toggle button through Javascript. Then I want to add three span tags inside it.
So, I am creating variable of span and trying to append it inside our very own basic FOR loop. Iteration count is 3 times.
Here's my basic code below. Please let me know what has been missing or misplaced that my span tag refuses to append more than once. I checked this in the inspect mode.
Then, I brought up console tab and the value of i was 3. Append is meant to append and NOT replace the element. Right ?
var $navbar_header = $('<div class="navbar-header"></div>');
var $button = $("<button></button>");
var $span = $('<span class="icon-bar"></span>');
for (var i = 0; i < 3; i++) {
$button.append($span);
}
$button.addClass('navbar-toggle');
$navbar_header.append($button);
$("#menu").append($navbar_header);
Here's a link to fiddle.
The DOM is a tree, where any element points to its parent (see parentNode). An element can have only one location. So when you append an element, you're removing it from its precedent location.
The solution here is either to clone the element:
$button.append($span.clone());
or just to create it in the loop:
for (var i = 0; i < 3; i++) {
$button.append('<span class="icon-bar"></span>');
}

Dynamically bond handler on multiple elements will call only last bond function

http://jsfiddle.net/7CV88/8/
On this snippet, I try to bind change to #r(Nth)e <input> element to change the contents of #r(N+1th)s <input> element. But when I change any Nth <input> element, the message shown is always "#r(last N)e change handler"
for(var i = 1; i < numRanges; i++){
$('#r'+i+'e').change(function(){
$('#messages').html('#r'+i+'e change handler');
$('#r'+(i+1)+'s').val($('#r'+i+'e').val());
});
}
You should use the so-called event data to pass the value of i into the onchange event handler:
for(var i = 1; i < numRanges; i++){
$('#r'+i+'e').change(i, function(e){
$('#messages').html('#r'+e.data+'e change handler');
$('#r'+(e.data+1)+'s').val($('#r'+e.data+'e').val());
});
}
Updated Demo.
Note: This just answers directly to your asked problem, I know your code is messy, fixing it is not the main thing to do.
This is a typical "closure" issue.
I was trying the simplest way to get out of the closure issue so I suggested this incorrect way:
for(var i = 1; i < numRanges; i++){
$('#r'+i+'e').change(function(){
var tempVariable = i;
$('#messages').html('#r'+tempVariable +'e change handler');
$('#r'+(tempVariable +1)+'s').val($('#r'+tempVariable +'e').val());
});
}
Thanks to metadings, I realized my mistake so I created a demo to test according to their advice:
var list = $("div");
for(var i = 0; i < list.length; i++){
$(list[i]).click((function(x){
return function(){alert(x);};
})(i));
}
http://jsfiddle.net/9qBXn/
HTH

Remove element from DOM [duplicate]

This question already has answers here:
JavaScript DOM remove element
(4 answers)
Closed 8 years ago.
I have a code:
<ul class='mates'>
<li class='m' id='1'>Jakub</li>
<li class='f' id='2'>Vinnie</li>
<li class='m' id='3'>David</li>
</ul>
This script selects one of the 'li' elements, according to users input:
<script>
var mates = document.getElementsByClassName('mates')[0];
for (var i=0; i< mates.childNodes.length; i++){
if(mates.children[i].innerHTML == 'Vinnie') alert("Got you! ID "+mates.children[i].id)
}
</script>
And I need to remove this element:
<script>
var mates = document.getElementsByClassName('mates')[0];
for (var i=0; i< mates.childNodes.length; i++){
if(mates.children[i].innerHTML == 'Vinnie') {
alert("Got you! ID "+mates.children[i].id);
parent = document.getElementsByClassName('mates');
mateToDelete = mates.children[i];
parent.removeChild(mateToDelete);
}
}
</script>
This is what I tried in several different ways but I always got error, e.g. " Cannot call method 'removeChild' of undefined". Any ideas?
You already have the parent node from your original getElementsByClassName, and you have your child through the loop that you've just performed.
As such, it's simple:
for (var i=0; i< mates.childNodes.length; i++){
if(mates.children[i].innerHTML == 'Vinnie'){
alert("Got you! ID "+mates.children[i].id)
mates.removeChild(mates.children[i]);
break;
}
}
For the sake of completeness (and to prevent further arguing in comments :P), if you are in fact potentially deleting multiple "Vinnie"'s from your list, then it would be better to make a list of those children you want to delete, then delete them after like so:
var toDelete=[],
i;
for (i=0; i< mates.childNodes.length; i++){
if(mates.children[i].innerHTML == 'Vinnie'){
alert("Got you! ID "+mates.children[i].id)
toDelete.push(mates.children[i]);
}
}
for (i=0; i<toDelete.length; i++){
mates.removeChild(toDelete[i]);
}
You don't need that parent variable. Delete it using this:
mates.removeChild(mateToDelete);
Fiddle: http://jsfiddle.net/3XeM5/2/
I also modified your for-loop to use:
for (var i=0; i< mates.children.length; i++){
The length of this (children.length) is 3, the length of childNodes is 7, so if nothing is found the loop will break!
Edit: If you want to delete multiple iterations of a specific element, remove the break; in the if-logic. If you're only looking for the first, leave the break.
Use This:
mates.removeChild(mates.children[i]);
Example:
http://jsfiddle.net/t9nCT/1/
You're retrieving a collection, so do,
parent[0].removeChild(mateToDelete);

Jquery wrapping my content with divs using append

for(var i=0; i<num_cols; i++)
{
//Wrapper for column
$('#cupcake-list').append('<div>');
//end wrapper
col_count++;
num_in_col = rowsInCol(total,num_perCol,col_count);
start = i*num_perCol;
end = start + num_in_col;
for(var d=start; d<end; d++)
{
$('#cupcake-list').append('<p>'+cupcakeData[d].name+'</p>');
}
//Wrapper for column
$('#cupcake-list').append('</div>');
//end wrapper
}
I just want to encapsulate my p tags within div tags to act as rows, however all I get are <div></div><p>ssdfsdf</p><p>sdfsdfdsf</p><div></div>etc....
What's the best way of doing it?
Start with a fragment so that you don't access the DOM more than once, and append it all at the end. You can skip the wrap by starting with your empty fragment, like so:
var $fragment;
for(var i=0; i<num_cols; i++)
{
$fragment = $('<div />');
col_count++;
num_in_col = rowsInCol(total,num_perCol,col_count);
start = i*num_perCol;
end = start + num_in_col;
for(var d=start; d<end; d++)
{
$fragment.append('<p>'+cupcakeData[d].name+'</p>');
}
//Wrapper for column
$('#cupcake-list').append($fragment);
//end wrapper
}
This is a much faster way to do it! Append parts of a string to an array and then you only have to update the DOM once.
var a = [];
for(var i=0; i<num_cols; i++)
{
a.push('<div>');
col_count++;
num_in_col = rowsInCol(total,num_perCol,col_count);
start = i*num_perCol;
end = start + num_in_col;
for(var d=start; d<end; d++)
{
a.push('<p>'+cupcakeData[d].name+'</p>');
}
a.push('</div>');
}
$('#cupcake-list').append(a.join(''));
EDIT:
I'll explain why yours wasn't working. When you were calling $('#cupcake-list').append('<div>'); you thought it would only add the opening div tag, but that is not the case. jQuery won't let you do this is because they want to make sure the html is valid after every function call. If you were to just add the opening div and then do some other stuff, the next closing div (</div>) in the document would close the div you just opened, changing the structure of the document entirely.
In summation:
$('#cupcake-list').append('<div>'); and $('#cupcake-list').append('</div>'); will both append <div></div> to the document. Also, access and update the DOM as if it costs you a million dollars because it is among the slowest things you can do in javascript.
jQuery has a method called .wrap, and some similar ones (.wrapAll).
If you are having the output that you showed, your code is not reaching the inner for, so you have a logic problem. I think your way of doing this is correct. When i need to build some structure on the fly i usually do the same thing.
JQuery append adds DOM nodes, not HTML. So you can accomplish your task like this:
for(var i=0; i<num_cols; i++)
{
col_count++;
num_in_col = rowsInCol(total,num_perCol,col_count);
start = i*num_perCol;
end = start + num_in_col;
for(var d=start; d<end; d++)
{
$('#cupcake-list').append($('<div></div>').append('<p>'+cupcakeData[d].name+'</p>'));
}
}
First, $('<div></div>') creates a new empty div element not yet attached to the page (you can also do $('<div>') as a shorthand if you want). Then .append('<p>...</p>') adds a p element inside the div. Finally, $('#cupcake-list').append(...) adds the whole div to the end of #cupcake-list.

Categories