Jquery clone elements: problems retaining checked radio buttons
Asked Answered
S

2

8

I've created this form that allows you to create multiple instances of a "thing"... Basically the necessary fields for the "thing" are all enclosed within a section. When the user clicks an "add more" button, I use Jquery's clone to copy the last section element in the series, and inserts it before the "add more" button. I clear out any fields in the new section with some Jquery.

The thing about this form I've built, is that you can fill out information in the fields of any section, but then when you decide you don't want a particular section anymore, you can just delete it. Then I've got a script that will go through the remaining sections, re-numbering all element attributes and elements, so that everything is appropriately numbered (easier to process the form with PHP after submission), and the remaining information you've entered will still be retained - even after elements and attributes being re-numbered.

Here's a pen: http://codepen.io/JonnyNineToes/pen/AgEax

Obligatory code:

// when the user clicks the "add more" button...
$('.add_btn').click(function(){
  // clone the previous element (a "repeatable" element), and insert it before the "add more" button
  $(this).prev('.repeatable').clone().insertBefore(this).html();
  // get the number of repeatable elements on the page
  var num = $('.repeatable').length;
  // again, get the previous element (a "repeatable" element), and change the header to reflect it's new index
  $(this).prev('.repeatable').children('h2').html('Person ' + num);
  // now, go through all text boxes within the last "repeatable" element...
  $('.repeatable').last().find('input').each(function(){
    // ...change their "structure" data attributes to reflect the index+1 value of the "repeatable" element
    dattr = $(this).data('structure') + num;
    $(this).attr({
      'id':dattr,
      'name':dattr
    // update the "for" attribute on the parent element (label)
    }).parent('label').attr('for',dattr);
    // clear the input field contents of the new "repeatable"
    // if the type of the input is "radio"...
    if ($(this).attr('type') == 'radio') {
      // remove the checked attribute
      /*$(this).removeAttr('checked');*/
    // for all other inputs...
    } else {
      // clear the value...
      $(this).val('');
    }
  });
  // run the "destroy" method... I forget why... just do it, and don't gimme no lip.
  destroy();
  updateRemoveLinks();
});

The problem I'm having is with radio buttons. If I click one of the radio buttons in the last section and then click "add more" to add another section after it, the radio buttons empty out (none selected) in the section that gets cloned, and instead are copied to the new section. Try the pen... click one of the radio buttons in the section, and then click "add more". You'll see what I mean.

I can't really figure out what I've done wrong here that it does this... Or if there's something I'm forgetting or have over-looked?

Sorcim answered 15/12, 2014 at 20:57 Comment(0)
W
15

First of all, to uncheck the new radio input you should use

$(this).prop("checked",false);

Second, your original radio input is getting unchecked because at the moment of cloning it, the new element has the same name and id of the original one, and you change it after cloning, which doesn't help.

A way to avoid this would be simply saving the original radio and resetting it after the cloning and name changing is done, like so:

$('.add_btn').click(function(){
    // clone the previous element (a "repeatable" element), and insert it before the "add more" button

    // save the original checked radio button
    var original = $('.repeatable').last().find(':checked');
    $(this).prev('.repeatable').clone().insertBefore(this).html();
    // get the number of repeatable elements on the page
    var num = $('.repeatable').length;
    // again, get the previous element (a "repeatable" element), and change the header to reflect it's new index
    $(this).prev('.repeatable').children('h2').html('Person ' + num);
    // now, go through all text boxes within the last "repeatable" element...
    $('.repeatable').last().find('input').each(function(){
      // ...change their "structure" data attributes to reflect the index+1 value of the "repeatable" element
      dattr = $(this).data('structure') + num;
      $(this).attr({
        'id':dattr,
        'name':dattr
      // update the "for" attribute on the parent element (label)
      }).parent('label').attr('for',dattr);
      // clear the input field contents of the new "repeatable"
      // if the type of the input is "radio"...
      if ($(this).attr('type') == 'radio') {
        // remove the checked attribute
        $(this).prop('checked',false);
      // for all other inputs...
      } else {
        // clear the value...
        $(this).val('');
      }
      // check if there's a checked radio button, and restore it
      if (original.length == 1) {
          original.prop('checked',true);
      }
    });

Working example: http://codepen.io/anon/pen/ByKEYJ?editors=101

I also added values to the radio buttons.

Watt answered 15/12, 2014 at 21:46 Comment(5)
Oh, you are the man! I've been puzzling over this for a few days. Thank you so much!Sorcim
Accepting the answer would be nice :)Watt
My bad. I tried upvoting it before, and I got a message saying I couldn't unless I "get more points" or something. I finally figured it out, though. Hopefully that resolves it. Thanks again for your help.Sorcim
No proble, glad to help!Watt
This saves me today. Hahaha. Thanks!Corm
S
0

I know, it is an old post, but I faces the same problem today and it looks like Jquery does not find elements with ':checked' only anymore.

I have changed it to:

var original = $('.whatever').last().find('input:checked');

and it works now.

Sevenfold answered 29/10, 2019 at 17:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.