javascriptjqueryhtmljquery-clone

How to CLONE a fieldset element and append it inside a form, correctly?


Jsfiddle here.

This is a simple example to reproduce my problem. Basically, I have a form (to read in data about multiple candidates), in which I have a fieldset (which takes input of data for one candidate), and then I have a button labelled ADD CANDIDATE. When it is clicked, the above fieldset should be cloned and copied below the above fieldset, so that the data about another candidate can be entered.

For the first candidate, each data field in the form is of the form allCandidatesArray[candidateNumber][fieldName], e.g. allCandidatesArray[0][nameInput] to facilitate the reading and further analysis of data submitted when the form is submitted. So in the Click handler/listener of ADD CANDIDATE button, I also do some programming to increment the candidateNumber in allCandidatesArray[candidateNumber][fieldName] when a new candidate is added.

But the main idea is to clone the previous fieldset and append the cloned fieldset below the previous fieldset. The problem is that the new thing which is appended is Not a fieldset. It is just three input elements. No labels, no nothing! What was cloned was a fieldset containing inputs and labels.

The question is WHY? And how do I fix this?

$(document).on("click", ".addMobileButton", function() {

	//alert(".addMobileButton clicked.");//check  

	var parentRow = $(this).closest(".row");

	var idOfThis = $(this).attr('id');
	//alert(idOfThis);//check
	//alert(idOfThis.length);//check
	var candidateNumber = idOfThis.slice(idOfThis.length-2, idOfThis.length-1);
	//alert("candidateNumber: " + candidateNumber);//check

	var nthMobileNumberOfThisCandidate = idOfThis.slice(-1);
	//alert("nthMobileNumberOfThiscandidate: " + nthMobileNumberOfThiscandidate);//check
	var newNthMobileOfThiscandidate = ++nthMobileNumberOfThisCandidate;
	//alert("newNthMobileNumberOfThisCandidate: " + newNthMobileOfThisCandidate);//check

	parentRow.after('<div id="rowAddedForCandidatesMobile" class="row valign-wrapper"><div class="input-field col l3"><input type="text" id="mobileInput'+candidateNumber+'" class="validate" name="allCandidatesArray['+candidateNumber+'][mobileInput][]"/><label for="mobileInput'+candidateNumber+'">Mobile</label></div><div class="col l1 addMobileButtonWrapper"><a id="addMobileButton'+candidateNumber+''+newNthMobileOfThisCandidate+'" class="btn-floating btn waves-light waves-effect blue white-text addMobileButton"><i class="material-icons">add</i></a></div></div>');


});







$(document).ready(function() {



	/*
	*
	*/
	$("a#addNewCandidateButton").on("click", function() {

		alert("#addNewCandidateButton clicked.");//check


		var previousFieldset = $(this).parent(".row").prevAll("fieldset.wrapper:first");
		//alert(previousFieldset[0].outerHTML);//check


		var fieldsetToClone = previousFieldset.clone();
		//alert(fieldsetToClone[0].outerHTML);//check


		var idOfAddMobileButton = fieldsetToClone.find(".addMobileButton").attr('id');
		//alert('idOfAddMobileButton: ' + idOfAddMobileButton);

		var candidateNumber = idOfAddMobileButton.slice(idOfAddMobileButton.length-2, idOfAddMobileButton.length-1);
		//alert("candidateNumber: " + candidateNumber);//check
		var candidateNumberIncremented = ++candidateNumber;
		//alert('candidateNumberIncremented: ' + candidateNumberIncremented);//check



		fieldsetToClone.find('input[type=text]').each(function(index) {
			var inputNameAttribute = $(this).attr('name');
			//alert('inputNameAttribute: ' + inputNameAttribute);//check

			var indexOfFirstOpeningBracket = inputNameAttribute.indexOf('[');
			//alert('indexOfFirstOpeningBracket: ' + indexOfFirstOpeningBracket);//check

			var indexOfFirstClosingBracket = inputNameAttribute.indexOf(']');
			//alert('indexOfFirstClosingBracket') + indexOfFirstClosingBracket;//check


			var inputNameAttributeArray = inputNameAttribute.split('');
			//alert('inputNameAttributeArray: ' + inputNameAttributeArray);//check

			//inputNameAttributeArray.splice(indexOfFirstOpeningBracket, indexOfFirstClosingBracket, candidateNumberIncremented);
			var lengthOfCandidate = (indexOfFirstClosingBracket - indexOfFirstOpeningBracket) -1;
			//alert('lengthOfCandidate: ' + lengthOfCandidate);//check
			inputNameAttributeArray.splice((indexOfFirstOpeningBracket+1), lengthOfCandidate, candidateNumberIncremented);
			//alert('inputNameAttributeArray after SPLICING:' + inputNameAttributeArray);//check

			inputNameAttributeModified = inputNameAttributeArray.join('');
			//alert('inputNameAttributeModified: ' + inputNameAttributeModified);//check

			$(this).attr('name', inputNameAttributeModified);

		});



		fieldsetToClone = fieldsetToClone.prepend('<div class="container"><div class="divider"></div></div>');



		fieldsetToClone = fieldsetToClone.find("input[type=text]").val('');

		previousFieldset.after(fieldsetToClone);

	});
	


});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.99.0/js/materialize.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.99.0/css/materialize.min.css" rel="stylesheet"/>




<form id="credentialsForm" action="" method="get">

	<fieldset class="container wrapper">
		<div class="row valign-wrapper">

			<div class="input-field col l3 offset-l1">
				<input type="text" id="nameInput0" class="validate" name="allCandidatesArray[0][nameInput]"/>
				<label class="blue-text" for="nameInput0">Name</label>
			</div>

			<div class="input-field col l3 offset-l1">
				<input type="text" id="ssnValueInput0" class="validate" name="allCandidatesArray[0][ssnValueInput]"/>
				<label class="blue-text" for="ssnValueInput0">SSN</label>
			</div>

		</div><!--.row-->



		<div class="row valign-wrapper">

			<div class="input-field col l3">
				<input type="text" id="mobileInput0" class="validate" name="allCandidatesArray[0][mobileInput][]"/>
				<label class="blue-text" for="mobileInput0">Mobile</label>
			</div>

			<div class="col l1 offset-l1 addMobileButtonWrapper">
				<a id="addMobileButton00" class="btn-floating btn waves-light waves-effect blue white-text addMobileButton"><i class="material-icons">add</i></a>
			</div>

		</div><!--.row-->



		<!--<div class="container"><div class="divider"></div></div>-->

		</fieldset><!--#wrapper-->






		<div class="row valign-wrapper">
			<a id="addNewCandidateButton" class="btn-flat waves-effect waves-light blue white-text col l2">Add Candidate</a>
		</div><!--.row-->


		

		<div class="row" id="submitFormRow">
			<div class="col l4 offset-l4">
				<button type="submit" class="btn waves-light waves-effect">Add Candidates</button>
			</div>
		</div><!--.row #s -->

</form>


Solution

  • You are overwriting cloned object in the following statements thus only inputs are appended.

    fieldsetToClone = fieldsetToClone.prepend('<div class="container"><div class="divider"></div></div>');
    fieldsetToClone = fieldsetToClone.find("input[type=text]").val('');
    

    Use

    fieldsetToClone.prepend('<div class="container"><div class="divider"></div></div>');
    fieldsetToClone.find("input[type=text]").val('');
    

    $(document).on("click", ".addMobileButton", function() {
      var parentRow = $(this).closest(".row");
      var idOfThis = $(this).attr('id');
      var candidateNumber = idOfThis.slice(idOfThis.length - 2, idOfThis.length - 1);
      var nthMobileNumberOfThisCandidate = idOfThis.slice(-1);
      var newNthMobileOfThiscandidate = ++nthMobileNumberOfThisCandidate;
      parentRow.after('<div id="rowAddedForCandidatesMobile" class="row valign-wrapper"><div class="input-field col l3"><input type="text" id="mobileInput' + candidateNumber + '" class="validate" name="allCandidatesArray[' + candidateNumber + '][mobileInput][]"/><label for="mobileInput' + candidateNumber + '">Mobile</label></div><div class="col l1 addMobileButtonWrapper"><a id="addMobileButton' + candidateNumber + '' + newNthMobileOfThisCandidate + '" class="btn-floating btn waves-light waves-effect blue white-text addMobileButton"><i class="material-icons">add</i></a></div></div>');
    });
    
    $("a#addNewCandidateButton").on("click", function() {
    
      var previousFieldset = $(this).parent(".row").prevAll("fieldset.wrapper:first");
      var fieldsetToClone = previousFieldset.clone();
      var idOfAddMobileButton = fieldsetToClone.find(".addMobileButton").attr('id');
      var candidateNumber = idOfAddMobileButton.slice(idOfAddMobileButton.length - 2, idOfAddMobileButton.length - 1);
    
      var candidateNumberIncremented = ++candidateNumber;
      fieldsetToClone.find('input[type=text]').each(function(index) {
        var inputNameAttribute = $(this).attr('name');
    
        var indexOfFirstOpeningBracket = inputNameAttribute.indexOf('[');
    
        var indexOfFirstClosingBracket = inputNameAttribute.indexOf(']');
    
        var inputNameAttributeArray = inputNameAttribute.split('');
        var lengthOfCandidate = (indexOfFirstClosingBracket - indexOfFirstOpeningBracket) - 1;
    
        inputNameAttributeArray.splice((indexOfFirstOpeningBracket + 1), lengthOfCandidate, candidateNumberIncremented);
    
        inputNameAttributeModified = inputNameAttributeArray.join('');
        $(this).attr('name', inputNameAttributeModified);
      });
    
      fieldsetToClone.prepend('<div class="container"><div class="divider"></div></div>');
    
      fieldsetToClone.find("input[type=text]").val('');
      previousFieldset.after(fieldsetToClone);
    
    });
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.99.0/js/materialize.min.js"></script>
    <link href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.99.0/css/materialize.min.css" rel="stylesheet" />
    
    
    
    
    <form id="credentialsForm" action="" method="get">
    
      <fieldset class="container wrapper">
        <div class="row valign-wrapper">
    
          <div class="input-field col l3 offset-l1">
            <input type="text" id="nameInput0" class="validate" name="allCandidatesArray[0][nameInput]" />
            <label class="blue-text" for="nameInput0">Name</label>
          </div>
    
          <div class="input-field col l3 offset-l1">
            <input type="text" id="ssnValueInput0" class="validate" name="allCandidatesArray[0][ssnValueInput]" />
            <label class="blue-text" for="ssnValueInput0">SSN</label>
          </div>
    
        </div>
        <!--.row-->
    
    
    
        <div class="row valign-wrapper">
    
          <div class="input-field col l3">
            <input type="text" id="mobileInput0" class="validate" name="allCandidatesArray[0][mobileInput][]" />
            <label class="blue-text" for="mobileInput0">Mobile</label>
          </div>
    
          <div class="col l1 offset-l1 addMobileButtonWrapper">
            <a id="addMobileButton00" class="btn-floating btn waves-light waves-effect blue white-text addMobileButton"><i class="material-icons">add</i></a>
          </div>
    
        </div>
        <!--.row-->
    
    
    
        <!--<div class="container"><div class="divider"></div></div>-->
    
      </fieldset>
      <!--#wrapper-->
    
    
    
    
    
    
      <div class="row valign-wrapper">
        <a id="addNewCandidateButton" class="btn-flat waves-effect waves-light blue white-text col l2">Add Candidate</a>
      </div>
      <!--.row-->
    
    
    
    
      <div class="row" id="submitFormRow">
        <div class="col l4 offset-l4">
          <button type="submit" class="btn waves-light waves-effect">Add Candidates</button>
        </div>
      </div>
      <!--.row #s -->
    
    </form>