2
<select id="one">
    <option id="one_val_a" value="one">one</option>
    <option id="two_val_a" value="two">two</option>
    <option id="three_val_a" value="three">three</option>
</select>

<span id="pin"></span>

How could I clone #one, make its id #two, and have its options ids as #one_val_b, #two_val_b, etc.

$('#one').clone(true, true).attr('id', 'two').appendTo('#pin');

That will atleast change the ID of the clone, but now how do change its options ids?

Jsfiddle: http://jsfiddle.net/C2zCZ/2/

Norse
  • 5,674
  • 16
  • 50
  • 86

5 Answers5

2

Here's another way, using a regex to replace the option id attributes, so it doesn't matter how many options the original select had:

$('#one').clone(true, true)
    .attr('id', 'two').appendTo('#pin')
    .find("option").each(function() {
        $(this).attr("id", $(this).attr("id").replace(/\_a$/, "_b"));
    });

Example fiddle

Rory McCrossan
  • 331,213
  • 40
  • 305
  • 339
2
$('#one')
    .clone(true, true)   // perform the clone
    .attr('id', 'two')  // change the id
    .appendTo('#pin')    // append to #pin
    .children()          // get all options
    .attr("id", function(i, value) {  // processing on ids
        // replacing last charecter with its next charecter
        return value.replace(/[a-z]$/, function(char, index) {
            return String.fromCharCode(char.charCodeAt(0) + 1);
        });
    });

Working Sample

thecodeparadox
  • 86,271
  • 21
  • 138
  • 164
  • +0.5 for putting every function on new line. I love this structure. +0.5 to letting me know that we can pass function in `replace()` – Jashwant May 29 '12 at 08:38
1
counter = 1;
$('#one').clone(true, true).attr('id', 'two').appendTo('#pin').find('option').each(function(){
    $(this).attr('id', 'option_id_' + counter++);
});

Here is your jsFiddle updated and working: http://jsfiddle.net/C2zCZ/4/

gabitzish
  • 9,535
  • 7
  • 44
  • 65
1

Another one-liner:

$('#one').clone(true, true).attr('id', 'two').each(function() {
    $(this).children().attr("id", function(i, value) {
        switch (i) {
            case 0: return "one_val_b";
            case 1: return "two_val_b";
            case 2: return "three_val_b";
        }
    });
}).appendTo('#pin');

DEMO: http://jsfiddle.net/C2zCZ/5/


Another, more flexible one-liner:

$('#one').clone(true, true).attr('id', 'two').appendTo('#pin')
    .children().attr("id", function(i, value) {

    var last = value.lastIndexOf("_") + 1;
    var char = value.substring(last).charCodeAt(0);
    return value.substring(0, last) + String.fromCharCode(char + 1);
});

DEMO: http://jsfiddle.net/C2zCZ/10/

VisioN
  • 143,310
  • 32
  • 282
  • 281
  • I don't understand how this works. You're using `each()` on a cloned element with a now unique id, of which there is only one. How does it know to iterate through each ` – Norse May 29 '12 at 08:06
  • @Norse This is that case when I used `each` only to get access to the cloned object through a callback function. JQuery iterates `option` elements 'automatically' when I set `attr` using callback function as well. However, in the second solution there is no `each`. – VisioN May 29 '12 at 08:14
1

Here's the one liner,

$('#one').clone(true).attr('id', 'two').children('option').attr('id',function(){
    return this.id.replace(/\a$/, 'b');
}).end().appendTo('#pin');

Fiddle

P.S.

  1. The second argument in clone() is copies the value in first argument (by default), so no need to pass second argument.

  2. I've used the end() because I think we should not access the after inserting into dom. (My approach should be faster but I haven't done a test)

Jashwant
  • 28,410
  • 16
  • 70
  • 105