1

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

11
  • pfff that's not possible :) Commented Aug 30, 2017 at 14:19
  • you have duplicated IDs... Commented Aug 30, 2017 at 14:23
  • why dont you use jquery to iterate and change it manually? Commented Aug 30, 2017 at 14:23
  • @gaetanoM I mean , Its okay to change structure , but I need those field replicated actually Commented Aug 30, 2017 at 14:26
  • @MateiMihai How about I get the html as object and iterate over it to see what I need and then add it back , Looks confusing but can you give me some other idea ?\ Commented Aug 30, 2017 at 14:28

5 Answers 5

1

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>

Sign up to request clarification or add additional context in comments.

8 Comments

I like the 2nd answer but there is one small problem when I clone everything gets clone the button and Heading also is there a way to fix that ?
@Vikram Changing the selector that I'm assigning to the base variable should do it. Ideally, you would just wrap the form fields in an element of some kind - probably a div. If that's not possible, I think it will take a little bit more creativity.
have a look on this line of code mentioned in one of the answer new_form.find('.f-row:first').remove(); I was trying to implement this in your code, But it doesn't work
If it worked, it would add extra manipulation each time the new form is created. I think we prefer to do the opposite: select all the f-row elements except the first. It will be a couple hours before I can work on it, but I think I see a fix.
@Vikram Header/button should now work correctly in the second snippet.
|
1

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.

4 Comments

actually its a form builder that generates the form , And I am trying to add my own hack to add some features :'(
So you could adjust the generated form (add [] to names and remove ids) when it was ready then clone it on click.
If I add [] then in the backend Ill have to change the api as well which accepts the complete form as Json , And creates a Table with the name of the input type as table header and value as value
Aaah then you need realy to adjust them as you say, check this one jsfiddle.net/56sfx5ur/7
1

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>

5 Comments

can you add that to the name as well like a new name contact_first_name_1, contact_first_nname_2
yes almost there , But next time when its cloning its doing clone of all the existing rather than just one , Like if there are two , then next clone it becomes 4 it should be 3 right
You can add simply the :first selector in order to clone only the first. It's not so hard. Thanks for sharing.
$('.cloneMe').on('click', function(e) { var idToAppend = $(this).data('id'); $(this).data('id', idToAppend + 1); $('div.render-form-editlayout-10').clone(":first").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);}) I tired this its not working
@Vikram Sorry. The :first selector goes only here: $('div.render-form-editlayout-10:first'). Snippet updated. Let me know. Thanks
0

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");
        });
    });

2 Comments

The catch is the name of the input type should be incremental like , name_1 , name_2 where's this ?
As I said , It just a basic Idea how it should be done. Also mentioned "Please change as you need". Unless he want us to do the job..
0

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);
});

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.