Search code examples
jqueryclone

how to clone form that includes text box display depended on drop down list


I have an issue with j query function to display text box depend on drop down list, if user select single: display "first name and last name once", if select double : display "first name and last name twice", its working for first row but not working with cloned rows, any advice please ?? FIDDLE

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
  <title></title>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
  <script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.3.1.min.js"></script>
  <script type="text/javascript">
    $(document).ready(function() {
      var genroomid = 2; // change 0 to the number you want to start with
      $(".add-row").click(function() {
        var $clone = $("ul.personal-details").first().clone();
        var $input = $clone.find('#roomid');
        $input.val(genroomid).attr('genroomid', +genroomid) // change fileid with any string you want 
        $clone.append("<button type='button' class='remove-row'>-</button>");
        $clone.insertBefore(".add-row");
        genroomid++; // increase id by 1
      });
      $(".form-style-9").on("click", ".remove-row", function() {
        $(this).parent().remove();
        genroomid--;
      });
      var blkofcod1 = "<select class='stretch' name='prefix[]'><option value='Mr'>Mr</option><option value='Ms'>Ms</option><option value='Child'>Child</option><option value='Infant'>Infant</option></select>";
      var blkofcod2 = "<input  name='fname[]'  type='text' class='stretch' placeholder='First Name' size='15'  maxlength='30' required >&nbsp;<input  name='lname[]' type='text' class='stretch' placeholder='Last Name' size='15' maxlength='30' required  >";
      var blkofcod3 = "<input name='nationality[]'  type='text' placeholder='Nationality' class='stretch' size='15' maxlength='30' required >";
      $('#roomtype').change(function() {
        var value = $(this).val();
        var toAppend = '';
        switch (value) {
          case 'None':
            toAppend = $("#container").html(toAppend);
            return;
            break;
          case 'Single':
            toAppend = blkofcod1 + blkofcod2 + blkofcod3;
            $("#container").html(toAppend);
            return;
            break;
          case 'Double':
            toAppend = blkofcod1 + blkofcod2 + blkofcod3 + "<br>" + blkofcod1 + blkofcod2 + blkofcod3;
            $("#container").html(toAppend);
            return;
            break;
          default:
            toAppend = $("#container").html(toAppend);
            return;
        }
      });

    });
  </script>
</head>

<body>
  <form id="form1">
    <span class="form-style-9">
    <ul class="personal-details">
    <div>
         <select id="roomtype" class="stretch"  name="roomtype[]" required="required">
         <option value="None"> None </option>
       <option value="Single"> Single </option>
         <option value="Double"> Double </option>
        </select>
       <div id="container"></div>

    </div>
    </ul>
    <button type="button" class="add-row">+ New Client</button>
    </span>
  </form>
</body>
</html>

Solution

  • With the slightest amount to tweaking of your code. The following works from my understanding of your question:

    Explanation:

    $('#roomtype').change(function () {}) became $(document).on('change', '#roomtype', function() {})

    The answer uses Delegated Event Handlers in jQuery. This point from the jQuery docs explains further.

    Event handlers are bound only to the currently selected elements; they must exist at the time your code makes the call to .on()

    In your code, only the first select field exists when the page initializes, and therefore any other select fields added later on (when then "+ New Client" button is clicked), aren't bound by the existing change handler.

    The delegated event handler implementation in the answer bind the event instead to the document. It could be any other DOM element as long as it is exists when the event handler was registered.

    By picking an element that is guaranteed to be present at the time the delegated event handler is attached, you can use delegated events to avoid the need to frequently attach and remove event handlers. This element could be the container element of a view in a Model-View-Controller design, for example, or document if the event handler wants to monitor all bubbling events in the document. The document element is available in the head of the document before loading any other HTML, so it is safe to attach events there without waiting for the document to be ready.

    Read more here: http://api.jquery.com/on/


    Secondly, the other change required to make the code work is how the #container is found in your code. Using $('#container') searches from the root of the DOM and in this case will almost always find the first element. Changing$('#container')to$(this).siblings('#container')finds the closest#container` to the changed select field.

    Fiddle: http://jsfiddle.net/5x1Lfedj/15/

    $(document).ready(function() {
      var genroomid = 2; // change 0 to the number you want to start with
      $(".add-row").click(function() {
        var $clone = $("ul.personal-details").first().clone();
        var $input = $clone.find('#roomid');
        $input.val(genroomid).attr('genroomid', +genroomid) // change fileid with any string you want 
        $clone.append("<button type='button' class='remove-row'>-</button>");
        $clone.insertBefore(".add-row");
        genroomid++; // increase id by 1
      });
    
    
      $(".form-style-9").on("click", ".remove-row", function() {
        $(this).parent().remove();
        genroomid--;
      });
    
      var blkofcod1 = "<select class='stretch' name='prefix[]'><option value='Mr'>Mr</option><option value='Ms'>Ms</option><option value='Child'>Child</option><option value='Infant'>Infant</option></select>";
      var blkofcod2 = "<input  name='fname[]'  type='text' class='stretch' placeholder='First Name' size='15'  maxlength='30' required >&nbsp;<input  name='lname[]' type='text' class='stretch' placeholder='Last Name' size='15' maxlength='30' required  >";
      var blkofcod3 = "<input name='nationality[]'  type='text' placeholder='Nationality' class='stretch' size='15' maxlength='30' required >";
    
      $(document).on('change', '#roomtype', function() {
        var value = $(this).val();
        var toAppend = '';
        var $container = $(this).siblings('#container')
    
        switch (value) {
          case 'None':
            toAppend = $container.html(toAppend);
            return;
            break;
    
          case 'Single':
            toAppend = blkofcod1 + blkofcod2 + blkofcod3;
            $container.html(toAppend);
            return;
            break;
    
          case 'Double':
            toAppend = blkofcod1 + blkofcod2 + blkofcod3 + "<br>" + blkofcod1 + blkofcod2 + blkofcod3;
            $container.html(toAppend);
            return;
            break;
    
          default:
            toAppend = $container.html(toAppend);
            return;
        }
      });
    
    });