0

I'm trying to clone a div and the input elements inside it. When I clone it, I would like all the ids to increment by one. I've made a fiddle to show you what I'm doing.

$("#add").click(function (e) {
    var amount = $('div.classes').length;
    var new_amount = amount + 1;
    var cloned_div = $('#class-' + amount);
    $(cloned_div).clone().attr('id', 'class-' + new_amount).insertAfter('#class-' + amount);
});

jsFiddle

So far I've cloned the whole div itself and the ids increment but the elements inside remain the same. How would I get all elements inside the div to increment by one?

SeanWM
  • 16,789
  • 7
  • 51
  • 83
  • 1
    @Diodeus Trust me, I know how to use this site. I've looked at multiple examples and I'm having trouble getting it to work the way I need it. – SeanWM Dec 19 '13 at 19:39
  • 2
    Just a tip - generally - having sequential IDs or IDs with numbers indicates a deeper design problem. Why do you need sequential IDs? – Benjamin Gruenbaum Dec 19 '13 at 19:47
  • @BenjaminGruenbaum Well I want to submit any amount of rows of data and save them as individual records in a table. Is there a better approach? All of this is going to be a form. – SeanWM Dec 19 '13 at 19:53
  • 1
    @SeanWM yes - there is. The best practice is - if your data has meaning you should back it up with a JS object. Another acceptable (but worse) solution is that for for the very list when you're adding it - keep a reference to it. What you're doing right now is creating new elements and adding them, then running a query on your own presentation layer to find the elements you yourself added - when you already had a reference to them in the first place. – Benjamin Gruenbaum Dec 19 '13 at 20:04
  • _"...The best practice is - if your data has meaning you should back it up with a JS object"_ What do yo mean by that? I've also realized that at some point I'll need to have the ability to edit these and loop them out (as well have the ability to add more to an existing group). Would what your saying help with this? – SeanWM Dec 19 '13 at 20:08
  • yes it would. We tend to reinvent the wheel but user interface architecture is a well known field of coding and people have figured out that in order to write consistent, testable code you need to separate between your presentation layer (the DOM, CSS etc) and your business logic. Your data should have a single source of truth. While I don't necessarily suggest using it, a really nice way to see SoC in action is to check out [the Knockout tutorial](http://learn.knockoutjs.com/) just to get perspective. Also check out http://martinfowler.com/eaaDev/uiArchs.html – Benjamin Gruenbaum Dec 19 '13 at 20:12

4 Answers4

1

You have cloned the entire div without modifying it's contents. Try something like:

$("#add").click(function (e) {
    var amount = $('div.classes').length;
    var new_amount = amount + 1;
    var cloned_div = $('#class-' + amount);
    $(cloned_div).clone().attr('id', 'class-' + new_amount).insertAfter('#class-' + amount).find('input').each(function (i, e) {
        $(e).attr('id', $(e).attr('id').replace(amount, new_amount));
    });
});

DEMO

tewathia
  • 6,890
  • 3
  • 22
  • 27
  • I feel I ought to add that `replace` will only work for the first occurrence of the `amount` string, which happens to be enough in this case, but if you want to have multiple replacements, use Regular Expressions – tewathia Dec 19 '13 at 19:49
  • What do you mean? This seems to work quite well. – SeanWM Dec 19 '13 at 19:51
  • @SeanWM Yes, this will work perfectly, but only in this case, because you want to change your id from `name-class-1` to `name-class-2`(with only one value of `amount` in the string). But if the id is `name-1-class-1-id-1`, `replace` would change it to `name-2-class-1-id-1`(only modifying the first instance, that is). So you could experiment with RegEx, or use the old `split('1').join('2')` routine. – tewathia Dec 19 '13 at 19:54
1

You can recursively replace all id's using find / replace:

$("#add").click(function (e) {
    var amount = $('div.classes').length;
    var new_amount = amount + 1;
    var cloned_div = $('#class-' + amount).clone();
    cloned_div.insertAfter('#class-' + amount);
    cloned_div.find('[id$="-' + amount + '"]').andSelf().each(function(index, child) {
        child.id = child.id.replace("-" + amount, "-" + new_amount);
    });
});

See jsFiddle

cloned_div.find('[id$="-' + amount + '"]') will search for all child elements having an id attribute ending on "-" + amount, .andSelf() will include the cloned div as you want to change the id there also. Then simply replace the number part in the id of each child (and self).

huysentruitw
  • 27,376
  • 9
  • 90
  • 133
0

Try adding this:

$('#class-' + new_amount + ' input:nth-child(1)').attr('id', 'name-class-' + new_amount);
$('#class-' + new_amount + ' input:nth-child(2)').attr('id', 'number-class-' + new_amount);
$('#class-' + new_amount + ' input:nth-child(3)').attr('id', 'book-class-' + new_amount);

just below your $(cloned_div).clone() statement.

See it in action:

http://jsfiddle.net/ZHHcA/1/

j2e
  • 556
  • 3
  • 10
-1

These other answers are close, but the problem with their solutions is the original ID prefixes are being lost: number-class-1 is becoming class-1 which is not ideal.

Here is a better option:

$("#add").click(function (e) {
    var amount = $('div.classes').length;
    var new_amount = amount + 1;
    var cloned_div = $('#class-' + amount);
    var $cloned = $(cloned_div).clone().attr('id', 'class-' + new_amount).insertAfter('#class-' + amount);

    $cloned.children().each(function(){
        var $child = $(this);
        var oldID = $child.attr('id');
        var newID = oldID.replace(/[0-9]+$/, new_amount); // replace just the number, leave the rest of the ID name in tact
        $child.attr('id', newID);
    })
});

And a working example

Kevin Jantzer
  • 9,215
  • 2
  • 28
  • 52