Cloning div with unique ID doesn't work - javascript

I'm pretty sure I'm close but I don't know what I'm missing:
var newId = 1;
$("#trigger").click(function(){
$("#new-div").attr('id', 'new-div' +newId++).clone().appendTo("#myDiv");
});
I set breakpoints: I can see the counter auto-incrementing, but the cloned div does not appear where it should. I get no errors. HTML for this:
<div id="secret-div" style="display: none;">
<div>This is new div number </div>
</div>
<p><a id="trigger" href="javascript:void(0);">Please, add an element</a></p>
<div id="myDiv"></div>

The issue is that you're changing the ID of your element before cloning and appending, resulting in 2 elements with the same ID, breaking your selector and code.
Fixed Live Demo
HTML:
<div id="secret-div" style="display:none;">
<div>This is new div number <span class="spnNewDivNumber"></span></div>
</div>
<p><a id="trigger" href="javascript:void(0);">Please, add an element</a></p>
<div id="myDiv"></div>​
JavaScript:
var newId = 1;
$("#trigger").click(function() {
var $newSecretDiv = $("#secret-div").clone().attr('id', 'new-div' + newId++);
$newSecretDiv.show().appendTo("#myDiv");
$newSecretDiv.find('.spnNewDivNumber').text(newId - 1);
});​

Your current code is applying the new id before the clone, which means it's changing the id of the existing div. This in turn means that the next time the click handler is called, there won't be a div matching the selector '#new-div'.
Try applying the id after either the clone, or after inserting it into the DOM:
var newId = 1;
$("#trigger").click(function(){
$("#new-div").clone().attr('id', 'new-div' +newId++).appendTo("#myDiv");
});
OR
var newId = 1;
$("#trigger").click(function(){
$("#new-div").clone().appendTo("#myDiv").attr('id', 'new-div' +newId++);
});

You are attempting to clone the #new-div unless your current div is named 'new-div'. Also you are changing the id of the original div rather than creating a new one with the generated id.

Related

JQuery clone is not working with class selector

Fiddle
I am trying to clone a span from the onClick() function of a button. First time this works fine but when I try second time it is not cloning. What am I doing wrong?
Here is the essence of my code.
$(document).ready(function(){
$('.addmachinerow').on('click',function(){
var edcname = $('.edc_name option:selected').val();
var machine_description = $("input[name='machine_description'").val();
var capacity = $("input[name='capacity'").val();
var voltage_level = $("input[name='voltage_level'").val();
var powertype = $("select[name='typeofpower'").val();
var edcautovalue = $('.ecaddingspan').attr('data-value');
//if($('#bank_increment').html() == '') $('#bank_increment').html('0'); else $('#bank_increment').html(parseInt($('#bank_increment').html())+1);
//if($('#bank_clickededit').html() == '') var bank_increment = $('#bank_increment').html(); else var bank_increment = $('#bank_clickededit').html();
$('.ecaddingspan').clone().appendTo('.edcparent');
//$('.bankname, .bankbranch , .IFSCcode , .bankaccno , .accsincefrom').val('');
var edc_details = {'edcname' : edcname, 'machine_description' : machine_description, 'capacity' : capacity, 'voltage_level' : voltage_level, 'powertype' : powertype }
//$('.bank_details_array').append(JSON.stringify(bank_details)+'&&');
});
});
Additionally:
How can i clone the entire sets on clicking the Total clone button ?
I need to save the values in array with different names. Is that possible ?
How can i clone the entire sets on clicking the Total clone button ?
You've to use event delagtion on() instead :
$('body').on('click','.addmachinerow', function(){
//Event code
})
Since the new .addmachinerow added to the page dynamically after the clone.
I need to save the values in array with different names is that possible ?
I suggest the use of the array name [] like :
<input name='machine_description[]' />
<input name='voltage_level[]' />
Hope this helps.
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("button").click(function(){
$('.cloneitem').not('.cloned').clone().addClass('cloned').appendTo('body');
});
});
</script>
</head>
<body>
<p class="cloneitem">This is a paragraph.</p>
<button>Clone all p elements, and append them to the body element</button>
</body>
</html>
The issue is a common misconception of JQuery selectors. If you play with ID selectors then switch to class selectors then you often don't notice a difference in behaviour. The ID selector doc says
ID Selector: If more than one element has been assigned the same ID, queries that use that ID will only select the first matched element in the DOM
whilst for the class selector
Class Selector: Selects all elements with the given class.
What this means is that when you clone the target element you get away with a subsequent ID selection (JQuery ignores the duplicates) but a subsequent class selection will trip you up if you were not expecting JQuery to return multiple matches. Class selectors are great for grouping elements but not so great for cloning.
While I am on the soap box - whenever you use the clone function you should consider and fix the potential duplicate ID and un-required class duplicates that you are producing. Duplicate ID's are definitely bad show - duplicate classes may actually be by design but you should still consider them.
In the code sample below I assign the class iAmSpartacus to the original span which the onClick() function then clones. Each clone also gets the iAmSpartacus class so I remove it from each new clone to ensure that the $(".iAmSpartacus") selector always returns a maximum of one element. The spans show their current class property to prove the point.
// this runs one - shows us classes of original span
var origSpan=$(".iAmSpartacus")
origSpan.html("My classes are: " + origSpan.prop("class"))
$("#daButton").on("click", function(e) {
var newSpan = $(".iAmSpartacus").clone();
newSpan.removeClass("iAmSpartacus"); // remove the dup targetting class
newSpan.appendTo('.edcparent');
newSpan.html("My classes are: " + newSpan.prop("class"))
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="daButton">Click me</button>
<div class="edcparent" style="border: 1px solid red;">
<span class="ecaddingspan iAmSpartacus" style="display: block;">I am a span</span>
</div>

Jquery assign second child attribute

Is there a way to assign nested div attribute with variable? Like
<div>
<div>
123456
</div>
</div>
Become
<div>
<div sectionid="123">
123456
</div>
</div>
BTW above component will be created by JavaScript.
I've tried something like this, but it didn't work.
var a = $('<div><div>123456</div></div>');
a.eq(":nth-child(2)").attr("sectionid", "123");
Try this snippet.
//FOR DOM HTML
console.log("FOR DOM HTML");
//1st way
$('#input > div').find('div').attr("sectionid","123");
console.log($('#input').html());
//2nd way
$('#input > div > div').attr("sectionid","321");
console.log($('#input').html());
//JS HTML
console.log("FOR JS OBJECT");
var input = $('<div><div>123456</div></div>');
//1st way
input.eq(0).children().attr('sectionid', '456');
console.log(input[0].outerHTML);
var input = $('<div><div>123456</div></div>');
//2nd way
$(input[0]).children().attr('sectionid', '789');
console.log(input[0].outerHTML);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="input">
<div>
<div>
123456
</div>
</div>
</div>
nth-child(2) maches elements that are the second child element of their parent. This is not the case for your div, it is the first element of the parent div.
.eq finds an element at a specific index. It is not the place to pass a selector.
The child selector, >, will find a child element, i.e. div>div will find a div that is an immediate child of a div.
Note that the code you've provided, $('<div></div>123456<div></div>');, doesn't create a DOM tree like the one you've pasted.
Update, now that the code is edited, the value of a is a div with a child div. Since a.find will perform a search within a, you don't have to use a child selector, but can find the div immediately:
a.find('div')
Just apply attribute to children. No complicated 'find', eq(), etc.
var a = $('<div><div>123456</div></div>');
a.children().attr('sectionid', '123');
$('body').append(a);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Why don't you add it in the first place? Not clear if you add it later!
$(document).ready(function() {
var sectionid = "123";
var a = $('<div><div sectionid="' + sectionid + '">123456</div></div>');
$('body').append(a);
});
div[sectionid]{
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Try this - I have added comments to the code to explain what is happening.
Inspect the element to see that the attribute is added
var a = $('<div><div>123456</div></div>'); // change this to match the structure you want
a.children() // .children gets the direct descendant (which should be the nested div
.eq(0) // gets the first in the array that is returned (if there are multiple direct descendents) - it is a 0 based index selector
.attr('sectionid', '123');
$('body').append(a)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
More information about .children()
More information about .eq()
try it :
$(document).ready(function(){
$("div").eq(1).attr("sectionid","123");
})

filter out which span to update

I have the following div collection in my HTML. It's designed to dynamically replicate according to user interaction.
<div class="bill-item">
<!-- Section for a single item -->
<div class="bill-item-img">
<!-- Section for Item pic -->
</div>
<div class="bill-item-description">
<!-- Section for Item description and pricing -->
<div class="bill-item-name">
<p class="bill-item-name-left">Normal Cofee</p><p class="bill-item-name-right">170.00</p>
<div class="clear"></div>
</div>
<div class="bill-item-price">
<span>170.00 USD</span>
</div>
<div class="bill-item-amount">
<span>2</span>
</div>
</div>
<div class="bill-amount-selection">
<!-- Section where the increment & decrement of item amount goes -->
<a class="amount-increase" href="#"></a>
<a class="amount-decrease" href="#"></a>
</div>
</div>
This is the HTML Rendered image of the elements.
I've written the following script to increase the bill-item-amount span value.
$(".amount-increase").click(function(){
x+=1;
$(".bill-item-amount span").html(x);
});
$(".amount-decrease").click(function(){
if(!x<=0){
x-=1;
$(".bill-item-amount span").html(x);
}
});
This works great but, it updates the value of both the span elements. what I want is to catch the event of the clicked element (which I do now) and increase the span value of the respective span. How can I filter out which span to update using javascript.?
Something like $(this).parents('.bill-item').find('.bill-item-amount span') should select the right element.
Inside your callback this is assigned to the eventSource.
You should walk the dom tree from the clicked element up until you reach the .bill-item element and the go down to the .bill-item-amount span node
$(".amount-increase").click(function(){
var $span = $(this).parent().parent().find(".bill-item-amount span");
var x = $span.html();
x+=1;
$span.html(x);
});
$(".amount-decrease").click(function(){
var $span = $(this).parent().parent().find(".bill-item-amount span");
var x = $span.html();
if(!x<=0){
x-=1;
$span.html(x);
}
});
Hi dimal update your code:
$(".amount-increase").click(function(){
x+=1;
$(".bill-item-amount").html(x);
});
$(".amount-decrease").click(function(){
if(!x<=0){
x-=1;
$(".bill-item-amount").html(x);
}
});
dont add span inside the selector [ it changes entire span values]
$(".amount-increase").click(function(){
x+=1;
$("use ur increase span id here").html(x); //
});
$(".amount-decrease").click(function(){
if(!x<=0){
x-=1;
$("use ur decrease span id here").html(x);
}
});
Inside each function the selector $(".bill-item-amount span") will find all the <span> amounts in the document. You can walk the DOM to find the correct <span> using jQuery or plain JavaScript. You seem to be using jQuery functions so my answer also uses jQuery.
The following code combines the two actions into a single function that increases or decreases the amount based on the class name of the <a> clicked. I also added a return false so that the browser will not follow the href="#" on the anchor.
$('.bill-amount-selection').on('click', 'a', function(){
var change = this.className == 'amount-increase' ? 1 : -1
var $amount = $(this).closest('.bill-item').find('.bill-item-amount span')
var amount = parseInt($amount.html(), 10) + change
$amount.html(amount < 0 ? 0 : amount)
return false
});
The use of .on() means that jQuery v1.7+ is required. I can supply a compatible function with lower jQuery versions if necessary.

jQuery: How to assign the right ID to a button dynamically

I have a JS/jQuery script that adds our leads (web contacts) to the DOM in a for loop. Everything works fine except for one thing. I want the body of the lead to be hidden upon the initial display, and then have a slideToggle button to display or hide the details That means dynamically adding click events to each button as it is created. The entire HTML (HTML and a JSON object mixed into the HTML) of the lead and the slideToggle button are all appended to a node in the DOM in the for loop. Here is the pertinent part of the for loop:
// Hide the body of the lead; just show the title bar and the first line
var dataID = data[i].id
var div = $('#row' + dataID);
var more = $('#more' + dataID);
div.hide();
// Create click event for each "+" button
more.click(function() {
div.slideToggle();
});
But when I click on the "+" button to reveal the details, it opens the last div, not the div I am trying to open. This is true no matter how many leads I have on the page. How do I get the click event to open the right div. If I console.log "div" in the click event, it gives me the ID of the last div, not the one I am clicking on. But if I console.log(div) outside the click event, it has the right ID.
Also, I was unsure whether I needed the "vars" in the loop or if I should declare them outside the loop.
Here is the HTML. It's one lead plus the beginning of the next lead, which I left closed in Firebug
<div id="lead1115">
<div id="learnmore">
<a id="more1115" class="more" href="#">+</a>
</div>
<div id="lead-info">
<div id="leadID">Lead ID# Date: March 27, 2012 11:26 AM (Arizona time)</div>
<div id="company">No company given</div>
<div id="name">Meaghan Dee</div>
<div id="email">
meaghan.dee#gmail.com
</div>
<br class="clearall">
<div>
<div id="row1115" style="display: none;">
<div id="phone">No phone given</div>
<div id="source">www.ulsinc.com/misc/expert-contact/</div>
<div id="cp-name">No channel partner chosen</div>
<br class="clearall">
<div id="location">
No location given
<br>
<strong>IP Address:</strong>
198.82.10.87
<br>
<span>Approximate Location: Blacksburg, Virginia, United States</span>
<br>
</div>
<div id="details">
<strong>Questions/Comments</strong>
<br>
We have the Professional Series Universal Laser Systems (laser cutter), and I wondered how I would order a high power density 2.0 replacement lens.nnThank you
</div>
</div>
</div>
</div>
<div id="learnmore">
<a id="1115|send_message" class="verify" href="#">Verify</a>
<a id="1115|send_message" class="markAsSpam" href="#">Spam</a>
<a id="1115|send_message" class="markAsDuplicate" href="#">Duplicate</a>
</div>
</div>
<br class="clearall">
<div id="lead1116">
<br class="clearall">
Try using .bind (or .on for 1.7+) and the data parameter.
more.bind("click",{target:div},function(e){
e.data.target.show();
}
or
more.on("click",{target:div},function(e){
e.data.target.show();
}
I think your basic problem is that div is common as a variable to all items. You have to separate the div's from each other by, for example, creating a local function and call it for each item. Something like:
function buildMore(div) {
more.click(function() {
div.slideToggle();
});
}
and in the loop call:
addMore(div);
p.s.
Whether you declare your variables inside or outside the loop doesn't matter: you still get the same variables.
This is because div variable gets changed and settles with the last value set in the loop.
Try this:
...
funciton createClick(div) {
return function() { div.slidToggle();
}
more.click( createClick(div) );
...
The variable div doesn't stay frozen with your click handler so it's value will be what it was at the end of the for loop and all click handlers will use the same value (which is what you're seeing).
There are a number of different ways to approach this and I thought all would be educational. Any one of them should work.
Idea #1 - Manufacture the row id from the clicked on more id
Use the id value on the clicked on link to manufacture the matching row ID. Since you create them in pairs, this can be done programmatically like this:
// Hide the body of the lead; just show the title bar and the first line
var dataID = data[i].id
$('#row' + dataID).hide();
$('#more' + dataID).click(function() {
// manufacture the row ID value from the clicked on id
var id = this.id.replace("more", "#row");
$(id).slideToggle();
});
Idea #2 - Use a function closure to "freeze" the values you want
Another way to do that is to create a function and closure that will capture the current value of div:
// Hide the body of the lead; just show the title bar and the first line
var dataID = data[i].id
var div = $('#row' + dataID).hide();
var more = $('#more' + dataID);
function addClick(moreItem, divItem) {
// Create click event for each "+" button
moreItem.click(function() {
divItem.slideToggle();
});
}
addClick(more, div);
Idea #3 - Use the HTML spatial relationship to find the row associated with a more
To make this work, you need to put a common class=lead on the top level lead div like this:
<div id="lead1115" class="lead">
And, a common class on each row:
<div id="row1115" class="row" style="display: none;">
Then, you can use the position relationships to find the row object that is in the same parent lead object as the clicked on more link like this:
// Hide the body of the lead; just show the title bar and the first line
var dataID = data[i].id
$('#row' + dataID).hide();
$('#more' + dataID).click(function() {
// find out common parent, then find the row in that common parent
$(this).closest(".lead").find(".row").slideToggle();
});
Idea #4 - Put the row ID as data on the more link
// Hide the body of the lead; just show the title bar and the first line
var dataID = data[i].id
$('#row' + dataID).hide();
$('#more' + dataID).data("row", "#row" + dataID).click(function() {
// get the corresponding row from the data on the clicked link
var rowID = $(this).data("row");
$(rowID).slideToggle();
});

jQuery display html in textarea exclude an element

I have 4 divs in a container. I want to display the html of the container which contains the divs in the textarea. I'm able to do this. The issue is, i don't want to get all the html of the container. I don't want to get #iv #three. I want to copy all the html of the container except div #three. I could use $('#three').remove() but i don't want to remove the div, I just don't want to copy it's html value to textarea. Check jsfiddle http://jsfiddle.net/rzfPP/
<div id="container">
<div id="one">test 1 </div>
<div id="two">test 2 </div>
<div id="three">test 3 </div>
<div id="four">test 4 </div>
</div>
<textarea id="save"></textarea>
var x = $('#container').html();
$('#save').val(x);
Try this
$("#container").clone().find("#three").remove().end().html();
http://jsfiddle.net/rzfPP/21/
/*
var x = $('#container').html();
$('#save').val(x);
*/
var lol = $('#container').clone()
$(lol).find('#three').remove();
$('#save').val(lol.html());
$('#container').clone().find('#three').remove().end().html();
Technically this is illegal since you are duplicating IDs, but it works fine.
http://jsfiddle.net/rzfPP/33/
Edit: Someone beat me to it :( Oh well.
var text = "";
$('#container div').each( function() {
if ( this.id != "three" ) {
text += $(this).html();
}
});
$('#save').val( text );
http://jsfiddle.net/rzfPP/31/
Basically you check the divs inside #container one by one, and check their id. If it's one you want, add their html to a string. Then at the end give that string as your textarea value.

Categories

Resources