Vikram Anand Bhushan
Vikram Anand Bhushan

Reputation: 4886

Html clone in Javascript

I have this HTML code

<div class="render-form-editlayout-10">
  <div class="formeo-render formeo" id="formeo-rendered-1">
    <div class="f-stage" id="afd81782-0230-4bbf-a39d-774ba6b3f6cf">
      <div class="f-row" id="78501c81-ce36-4703-ae99-7e086a95c0d7">
        <div class="f-render-column" id="71dac9e6-03ed-4294-b60f-8d2466d1aa17" style="width: 100%;">
          <h1 id="5baec553-c31c-4d0b-a138-6d338deb1f4b">Contact</h1></div>
      </div>
      <div class="f-row" id="44a64baa-64e5-44ad-af51-bed0a0abf3ae">
        <div class="f-render-column" id="95128be9-b2cb-4c82-aea2-4dd84b247ac4" style="width: 50%;">
          <div class="f-field-group">
            <label for="293053b9-9769-4b06-8156-01d7a15995b3">First name</label>
            <input type="text" name="contact_first_name" id="293053b9-9769-4b06-8156-01d7a15995b3">
          </div>
        </div>
        <div class="f-render-column" id="17193931-bd81-452e-95ba-591f2246eb37" style="width: 50%;">
          <div class="f-field-group">
            <label for="3d276a4f-1dff-4594-8fe8-56ac1acf58e4">Sur Name</label>
            <input type="text" name="contact_sur_name" id="3d276a4f-1dff-4594-8fe8-56ac1acf58e4">
          </div>
        </div>
      </div>
      <div class="f-row" id="9ba99767-5ea4-40b2-b0a4-df252b210a3c">
        <div class="f-render-column f-render-column f-render-column" id="4fe9abe0-6944-4504-896b-44adfa58ade8" style="width: 100%;">
          <div class="f-field-group">
            <label for="8379e16f-f468-47c4-8149-ba606d4310ad">Email</label>
            <input type="text" name="contact_email" id="8379e16f-f468-47c4-8149-ba606d4310ad">
          </div>
        </div>
      </div>
      <div class="f-row" id="e5bd3083-fb17-4453-a875-b6024db9461f">
        <div class="f-render-column f-render-column f-render-column" id="b87b0913-9286-4233-afcb-e568e3017092" style="width: 100%;">
          <div class="f-field-group">
            <label for="a54606a2-679b-4e9c-8b90-f5f2c6e79ef0">Phone</label>
            <input type="number" class="form-control" name="contact_phone" id="a54606a2-679b-4e9c-8b90-f5f2c6e79ef0">
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
<div class="render-form-editlayout-10">
  <div class="formeo-render formeo" id="formeo-rendered-1">
    <div class="f-stage" id="afd81782-0230-4bbf-a39d-774ba6b3f6cf">
      <div class="f-row" id="44a64baa-64e5-44ad-af51-bed0a0abf3ae">
        <div class="f-render-column" id="95128be9-b2cb-4c82-aea2-4dd84b247ac4" style="width: 50%;">
          <div class="f-field-group">
            <label for="293053b9-9769-4b06-8156-01d7a15995b3">First name</label>
            <input type="text" name="contact_first_name" id="293053b9-9769-4b06-8156-01d7a15995b3">
          </div>
        </div>
        <div class="f-render-column" id="17193931-bd81-452e-95ba-591f2246eb37" style="width: 50%;">
          <div class="f-field-group">
            <label for="3d276a4f-1dff-4594-8fe8-56ac1acf58e4">Sur Name</label>
            <input type="text" name="contact_sur_name" id="3d276a4f-1dff-4594-8fe8-56ac1acf58e4">
          </div>
        </div>
      </div>
      <div class="f-row" id="9ba99767-5ea4-40b2-b0a4-df252b210a3c">
        <div class="f-render-column f-render-column f-render-column" id="4fe9abe0-6944-4504-896b-44adfa58ade8" style="width: 100%;">
          <div class="f-field-group">
            <label for="8379e16f-f468-47c4-8149-ba606d4310ad">Email</label>
            <input type="text" name="contact_email" id="8379e16f-f468-47c4-8149-ba606d4310ad">
          </div>
        </div>
      </div>
      <div class="f-row" id="e5bd3083-fb17-4453-a875-b6024db9461f">
        <div class="f-render-column f-render-column f-render-column" id="b87b0913-9286-4233-afcb-e568e3017092" style="width: 100%;">
          <div class="f-field-group">
            <label for="a54606a2-679b-4e9c-8b90-f5f2c6e79ef0">Phone</label>
            <input type="number" class="form-control" name="contact_phone" id="a54606a2-679b-4e9c-8b90-f5f2c6e79ef0">
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
<button class="btn btn-success cloneMe " data-id="10">+</button>

Js Fiddle for above code

So when you click the + button it should clone the html .

Now When It's cloned I want to make it look like this

Js Fiddle

The catch is the name of the input type should be incremental like , name_1 , name_2

I am really confused how to do that

Update

As mentioned in one of the answers below the Id of the div can be accssed using the data-id of the button . Then My question is ? is it possible to just get the input type and change there name+data-id and append ?

enter image description here

Upvotes: 1

Views: 471

Answers (5)

Mic
Mic

Reputation: 4004

It's kind of a flagrant abuse of template literals, but here's a simplified version just for fun - as a general practice I would lean toward an actual templating library for this sort of thing (Underscore has a fairly easy template function, for example).

addSubform = (function(){
  n = 0
  container = $('#container')
  return function(){
    n += 1
    container.append(`<div class="subform" id="subform${n}">
First Name: <input type="text" id="fname_${n}" name="fname_${n}" /><br />
Surname: <input type="text" id="sname_${n}" name="sname_${n}" /><br />
<hr />
</div>`)
  }
})()

$(document).ready(function(){
  addSubform()
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="container">

</div>
<button onclick="addSubform()">+</button> 

Here's another option that I generally wouldn't recommend if you have any viable alternatives, but it uses regex to find the name attributes and append a suffix. It doesn't work quite as intended, but I think it does enough to illustrate the concept. If you inspect with your dev tools, you'll see that the name attributes are being incremented.

I used closures in both examples in order to manage scope. That's a personal preference, and is not critical to solving your particular issue.

//I would probably not put this in a global,
//but since it's unclear it's being determined client-side,
//I'm considering that concern out of scope for this question.
//var formNum 

buildForm = function(formNum) {
  /*A lot going on in this line - call the Array's slice method
  against the HTML element collection matching the class name "f-row",
  supplying an index (zero-based) of 1 for the start. This effectively
  removes the first element. Then use .reduce to convert the HTML of
  the remaining elements to a string.
  */
  var base = Array.prototype.slice.call(
    document.getElementsByClassName('render-form-editlayout-' + formNum)[0].getElementsByClassName('f-row'), 1)
    .reduce(function(b,e){return b += e.outerHTML},"")
  
  var suffix = 0
  return function() {
    suffix += 1
    return base.replace(/name="([a-z_]+)"/gm,'name="$1_' + suffix + '"')
  }
}

addForm = function(formNum, builder){
  var container = document.getElementsByClassName('render-form-editlayout-' + formNum)[0].getElementsByClassName('f-stage')[0]
  return function() {
    container.innerHTML += builder()
  }
}

makeCloneEvent = function(num) {
	return addForm(num, buildForm(num))
}

$('.cloneMe').each(
	function() {
    el = $(this)
    el.on('click', makeCloneEvent(el.data('id')))
  }
)
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="form_container">
<div class="render-form-editlayout-10 form-model">
  <div class="formeo-render formeo" id="formeo-rendered-1">
    <div class="f-stage" id="afd81782-0230-4bbf-a39d-774ba6b3f6cf">
      <div class="f-row" id="78501c81-ce36-4703-ae99-7e086a95c0d7">
        <div class="f-render-column" id="71dac9e6-03ed-4294-b60f-8d2466d1aa17" style="width: 100%;">
          <h1 id="5baec553-c31c-4d0b-a138-6d338deb1f4b">Contact</h1></div>
      </div>
      <div class="f-row" id="44a64baa-64e5-44ad-af51-bed0a0abf3ae">
        <div class="f-render-column" id="95128be9-b2cb-4c82-aea2-4dd84b247ac4" style="width: 50%;">
          <div class="f-field-group">
            <label for="293053b9-9769-4b06-8156-01d7a15995b3">First name</label>
            <input type="text" name="contact_first_name" id="293053b9-9769-4b06-8156-01d7a15995b3">
          </div>
        </div>
        <div class="f-render-column" id="17193931-bd81-452e-95ba-591f2246eb37" style="width: 50%;">
          <div class="f-field-group">
            <label for="3d276a4f-1dff-4594-8fe8-56ac1acf58e4">Sur Name</label>
            <input type="text" name="contact_sur_name" id="3d276a4f-1dff-4594-8fe8-56ac1acf58e4">
          </div>
        </div>
      </div>
      <div class="f-row" id="9ba99767-5ea4-40b2-b0a4-df252b210a3c">
        <div class="f-render-column f-render-column f-render-column" id="4fe9abe0-6944-4504-896b-44adfa58ade8" style="width: 100%;">
          <div class="f-field-group">
            <label for="8379e16f-f468-47c4-8149-ba606d4310ad">Email</label>
            <input type="text" name="contact_email" id="8379e16f-f468-47c4-8149-ba606d4310ad">
          </div>
        </div>
      </div>
      <div class="f-row" id="e5bd3083-fb17-4453-a875-b6024db9461f">
        <div class="f-render-column f-render-column f-render-column" id="b87b0913-9286-4233-afcb-e568e3017092" style="width: 100%;">
          <div class="f-field-group">
            <label for="a54606a2-679b-4e9c-8b90-f5f2c6e79ef0">Phone</label>
            <input type="number" class="form-control" name="contact_phone" id="a54606a2-679b-4e9c-8b90-f5f2c6e79ef0">
          </div>
        </div>
      </div>
    </div>
 </div>
 <button  class="cloneMe" data-id='10'>Add +</button>

Upvotes: 1

gaetanoM
gaetanoM

Reputation: 42044

My proposal is:

  • clone the render-form-editlayout-10 div
  • for each sub cloned element with an id add a postfix using the button data-id
  • increment the button data-id

$('.cloneMe').on('click', function (e) {
    var idToAppend = $(this).data('id');
    $(this).data('id', idToAppend + 1);
    $('div.render-form-editlayout-10:first').clone().find('[id]').attr('id', function (idx, val) {
        var newId = (this.name == undefined) ? val + idToAppend : this.name + '_' + idToAppend;
        if ((this.name != undefined)) {
            $(this).attr('name', newId);
            console.log('For elements with name the new ID is: ' +
                    newId + ' new Name is: ' + newId);
        }
        return newId;
    }).closest('div.render-form-editlayout-10').insertBefore(this);
})
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

<div class="render-form-editlayout-10">
    <div class="formeo-render formeo" id="formeo-rendered-1">
        <div class="f-stage" id="afd81782-0230-4bbf-a39d-774ba6b3f6cf">
            <div class="f-row" id="78501c81-ce36-4703-ae99-7e086a95c0d7">
                <div class="f-render-column" id="71dac9e6-03ed-4294-b60f-8d2466d1aa17" style="width: 100%;">
                    <h1 id="5baec553-c31c-4d0b-a138-6d338deb1f4b">Contact</h1></div>
            </div>
            <div class="f-row" id="44a64baa-64e5-44ad-af51-bed0a0abf3ae">
                <div class="f-render-column" id="95128be9-b2cb-4c82-aea2-4dd84b247ac4" style="width: 50%;">
                    <div class="f-field-group">
                        <label for="293053b9-9769-4b06-8156-01d7a15995b3">First name</label>
                        <input type="text" name="contact_first_name" id="293053b9-9769-4b06-8156-01d7a15995b3">
                    </div>
                </div>
                <div class="f-render-column" id="17193931-bd81-452e-95ba-591f2246eb37" style="width: 50%;">
                    <div class="f-field-group">
                        <label for="3d276a4f-1dff-4594-8fe8-56ac1acf58e4">Sur Name</label>
                        <input type="text" name="contact_sur_name" id="3d276a4f-1dff-4594-8fe8-56ac1acf58e4">
                    </div>
                </div>
            </div>
            <div class="f-row" id="9ba99767-5ea4-40b2-b0a4-df252b210a3c">
                <div class="f-render-column f-render-column f-render-column" id="4fe9abe0-6944-4504-896b-44adfa58ade8" style="width: 100%;">
                    <div class="f-field-group">
                        <label for="8379e16f-f468-47c4-8149-ba606d4310ad">Email</label>
                        <input type="text" name="contact_email" id="8379e16f-f468-47c4-8149-ba606d4310ad">
                    </div>
                </div>
            </div>
            <div class="f-row" id="e5bd3083-fb17-4453-a875-b6024db9461f">
                <div class="f-render-column f-render-column f-render-column" id="b87b0913-9286-4233-afcb-e568e3017092" style="width: 100%;">
                    <div class="f-field-group">
                        <label for="a54606a2-679b-4e9c-8b90-f5f2c6e79ef0">Phone</label>
                        <input type="number" class="form-control" name="contact_phone" id="a54606a2-679b-4e9c-8b90-f5f2c6e79ef0">
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

<button class="btn btn-success cloneMe" data-id="10">+</button>

Upvotes: 1

Ramy Nasr
Ramy Nasr

Reputation: 2527

In my opinion the best way to do this if you can not use the name='something[]' pattern suggested in previous answers, is to do the following:

  1. Have a template of all the form elements you want to clone ( all the markup )
  2. Have a string in this markup that should be replaced with the incremental index every time you are cloning. ( e.g. <input name="firstname__index__" ... /> )
  3. Every time you want to clone, just search and replace all instances of __index__ in your HTML with your increment before appending the new HTML to your page.

Consider something like that:

$clonedForm.find('input').each(function (i, ele) {
    var $input = $(ele);
    var name = $input.attr('name').replace('__index__', increment);
    $input.attr('name', name);
});

Upvotes: 0

Zakaria Acharki
Zakaria Acharki

Reputation: 67505

Updated fiddle.

It will be more efficient to name your fields as array using [] like :

<div class="render-form-editlayout-10 form-model">
  <div class="formeo-render formeo" id="formeo-rendered-1">
    <div class="f-stage" id="afd81782-0230-4bbf-a39d-774ba6b3f6cf">
      <div class="f-row" id="78501c81-ce36-4703-ae99-7e086a95c0d7">
        <div class="f-render-column" id="71dac9e6-03ed-4294-b60f-8d2466d1aa17" style="width: 100%;">
          <h1 id="5baec553-c31c-4d0b-a138-6d338deb1f4b">Contact</h1></div>
      </div>
      <div class="f-row" id="44a64baa-64e5-44ad-af51-bed0a0abf3ae">
        <div class="f-render-column" id="95128be9-b2cb-4c82-aea2-4dd84b247ac4" style="width: 50%;">
          <div class="f-field-group">
            <label for="293053b9-9769-4b06-8156-01d7a15995b3">First name</label>
            <input type="text" name="contact_first_name[]" id="293053b9-9769-4b06-8156-01d7a15995b3">
          </div>
        </div>
        <div class="f-render-column" id="17193931-bd81-452e-95ba-591f2246eb37" style="width: 50%;">
          <div class="f-field-group">
            <label for="3d276a4f-1dff-4594-8fe8-56ac1acf58e4">Sur Name</label>
            <input type="text" name="contact_sur_name[]" id="3d276a4f-1dff-4594-8fe8-56ac1acf58e4">
          </div>
        </div>
      </div>
      <div class="f-row" id="9ba99767-5ea4-40b2-b0a4-df252b210a3c">
        <div class="f-render-column f-render-column f-render-column" id="4fe9abe0-6944-4504-896b-44adfa58ade8" style="width: 100%;">
          <div class="f-field-group">
            <label for="8379e16f-f468-47c4-8149-ba606d4310ad">Email</label>
            <input type="text" name="contact_email[]" id="8379e16f-f468-47c4-8149-ba606d4310ad">
          </div>
        </div>
      </div>
      <div class="f-row" id="e5bd3083-fb17-4453-a875-b6024db9461f">
        <div class="f-render-column f-render-column f-render-column" id="b87b0913-9286-4233-afcb-e568e3017092" style="width: 100%;">
          <div class="f-field-group">
            <label for="a54606a2-679b-4e9c-8b90-f5f2c6e79ef0">Phone</label>
            <input type="number" class="form-control[]" name="contact_phone" id="a54606a2-679b-4e9c-8b90-f5f2c6e79ef0">
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
<button class="btn btn-success cloneMe " data-id="10">+</button>

Then by adding a class to your main div example form-model you could clone the form by attaching the click event to the button like :

$('.cloneMe').click(function(){
  var new_form = $('.form-model').clone(true); //Clone form

  new_form.find('.f-row:first').remove(); //Remove title 'Contact' from the clone

  $('.form-model').append(new_form); //append new form
});

NOTE : The only problem will be the duplicate id's when id attribute should be unique, so if you could avoid the id's in the original HTML code it will be better to validate your HTML.

Hope this helps.

Upvotes: 1

MMRahman
MMRahman

Reputation: 319

I did a small change on your code to make it work. I hope you don't mind. Please change as you need.

JSfiddle

      <div class="render-form-editlayout-10">
        <div class="formeo-render formeo" id="formeo-rendered-1">

          <div class="f-stage" id="afd81782-0230-4bbf-a39d-774ba6b3f6cf">
            <div class="f-row" id="78501c81-ce36-4703-ae99-7e086a95c0d7">
              <div class="f-render-column" id="71dac9e6-03ed-4294-b60f-8d2466d1aa17" style="width: 100%;">
                <h1 id="5baec553-c31c-4d0b-a138-6d338deb1f4b">Contact</h1></div>
            </div>

            <div id="cloneme">
            <div class="f-row" id="44a64baa-64e5-44ad-af51-bed0a0abf3ae">
              <div class="f-render-column" id="95128be9-b2cb-4c82-aea2-4dd84b247ac4" style="width: 50%;">
                <div class="f-field-group">
                  <label for="293053b9-9769-4b06-8156-01d7a15995b3">First name</label>
                  <input type="text" name="contact_first_name" id="293053b9-9769-4b06-8156-01d7a15995b3">
                </div>
              </div>
              <div class="f-render-column" id="17193931-bd81-452e-95ba-591f2246eb37" style="width: 50%;">
                <div class="f-field-group">
                  <label for="3d276a4f-1dff-4594-8fe8-56ac1acf58e4">Sur Name</label>
                  <input type="text" name="contact_sur_name" id="3d276a4f-1dff-4594-8fe8-56ac1acf58e4">
                </div>
              </div>
            </div>
            <div class="f-row" id="9ba99767-5ea4-40b2-b0a4-df252b210a3c">
              <div class="f-render-column f-render-column f-render-column" id="4fe9abe0-6944-4504-896b-44adfa58ade8" style="width: 100%;">
                <div class="f-field-group">
                  <label for="8379e16f-f468-47c4-8149-ba606d4310ad">Email</label>
                  <input type="text" name="contact_email" id="8379e16f-f468-47c4-8149-ba606d4310ad">
                </div>
              </div>
            </div>
            <div class="f-row" id="e5bd3083-fb17-4453-a875-b6024db9461f">
              <div class="f-render-column f-render-column f-render-column" id="b87b0913-9286-4233-afcb-e568e3017092" style="width: 100%;">
                <div class="f-field-group">
                  <label for="a54606a2-679b-4e9c-8b90-f5f2c6e79ef0">Phone</label>
                  <input type="number" class="form-control" name="contact_phone" id="a54606a2-679b-4e9c-8b90-f5f2c6e79ef0">
                </div>
              </div>
            </div>
            </div>
          </div>
        </div>
      </div>

<button id= "clone" class="btn btn-success cloneMe " data-id="10">+</button>


    $(document).ready(function(){
        $("#clone").click(function(){
            $("#cloneme").clone().appendTo("#afd81782-0230-4bbf-a39d-774ba6b3f6cf");
        });
    });

Upvotes: 0

Related Questions