简体   繁体   中英

Dynamically add set of inputs to html form

I am currently creating a HTML form, I have a section in which contains 8 text inputs. This is the section so far:

<div class="form-title"><h3>Clinical Information</h3></div>
    <div class="form-title">Time Assesed:</div>
    <input class="form-field" type="time" name="timeassessd" /><br />
    <div class="form-title">Blood Pressure:</div>
    <input class="form-field" type="text" name="bp" /><br />
    <div class="form-title">Pulse:</div>
    <input class="form-field" type="date" name="pulse" /><br />
    <div class="form-title">Resp. Rate:</div>
    <input class="form-field" type="text" name="breathing" /><br />
    <div class="form-title">Temp:</div>
    <input class="form-field" type="text" name="temp" /><br />
    <div class="form-title">SPO2:</div>
    <input class="form-field" type="text" name="spo2" /><br />
    <div class="form-title">GCS:</div>
    <input class="form-field" type="text" name="gcs" /><br />
    <div class="form-title">AVPU:</div>
    <input class="form-field" type="text" name="avpu" /><br />

What I need is to have a button that when the user presses the button it will create another section identical to the one above adding the fields to the form. Each form will also need a number on the end of the name. I have looked around at different forums but I cant find one with a whole section to add in just individual inputs which doesn't help me here. Thanks.

You need to make a JS function to add the section. the function would look something like this:

function add_section() {
        new_row = "";
        new_row += "";
        new_row += '<div class="form-title"><h3>Clinical Information</h3></div>';
        new_row += '<div class="form-title">Time Assesed:</div>';
        new_row += '<input class="form-field" type="time" name="timeassessd" /><br />';
        new_row += '<div class="form-title">Blood Pressure:</div>';
        new_row += '<input class="form-field" type="text" name="bp" /><br />';
        new_row += '<div class="form-title">Pulse:</div>';
        new_row += '<input class="form-field" type="date" name="pulse" /><br />';
        new_row += '<div class="form-title">Resp. Rate:</div>';
        new_row += '<input class="form-field" type="text" name="breathing" /><br />';
        new_row += '<div class="form-title">Temp:</div>';
        new_row += '<input class="form-field" type="text" name="temp" /><br />';
        new_row += '<div class="form-title">SPO2:</div>';
        new_row += '<input class="form-field" type="text" name="spo2" /><br />';
        new_row += '<div class="form-title">GCS:</div>';
        new_row += '<input class="form-field" type="text" name="gcs" /><br />';
        new_row += '<div class="form-title">AVPU:</div>';
        new_row += '<input class="form-field" type="text" name="avpu" /><br />';

        var pos = $("selecter"); //element selecter after which you need to add the section
        $(pos).after(new_row);
}

And then on the click of the button, call this function. It will work.

Also the name of input fields should be an array ex: name="avpu[]" If not using array, the post method would only get the value of the last input element having same names.

Could you post the whole form?

What you can do, if you're using jQuery, is, that you clone the jQuery node of the form and than manipulate the input names, and than append the content to your form.
Something like that:

var num = 1;
function add_form_elements(num) {
   var clonedForm = $('#id_of_the_form').clone();
   clonedForm.find('input').each(function(id, elm) {
     elm.attr("name",elm.attr("name") + num);
   });
   $('#id_of_the_form').append(clonedForm.innerHTML);
   num++;
});

Than you need to add an EventListener to your button and bind the add_form_elements function to it.

Make new div, which content all you want to duplicate and is invisible.

<div class="copyable" style="display: none;">
  <div class="form-title"><h3>Clinical Information</h3></div>
  <div class="form-title">Time Assesed:</div>
  <input class="form-field" type="time" name="timeassessd" /><br />
  <div class="form-title">Blood Pressure:</div>
  <input class="form-field" type="text" name="bp" /><br />
  <div class="form-title">Pulse:</div>
  <input class="form-field" type="date" name="pulse" /><br />
  <div class="form-title">Resp. Rate:</div>
  <input class="form-field" type="text" name="breathing" /><br />
  <div class="form-title">Temp:</div>
  <input class="form-field" type="text" name="temp" /><br />
  <div class="form-title">SPO2:</div>
  <input class="form-field" type="text" name="spo2" /><br />
  <div class="form-title">GCS:</div>
  <input class="form-field" type="text" name="gcs" /><br />
  <div class="form-title">AVPU:</div>
  <input class="form-field" type="text" name="avpu" /><br />
</div>

In JS file:

function add_elm(){
  var content = $('.copyable').html(),
      $elm = $('.elm'); //element where you want to add copyable content
  $elm.append(content);
}

Note: append use for appending html inside parent node. If you want add html exactly after other elm, just use after(content) at the end of code above.

One approach to your problem, using plain JavaScript is the following (bear in mind that this does require a change to your HTML, in that the section containing the <input> elements you wish to duplicate requires a class-name (here it's "clinicalInformation" , but adjust to your own requirements - remembering to change the selector held in the <button> elements' data-duplicates attribute):

// the event is passed automagically from the addEventListener()
// method:
function duplicate(event) {
  // preventing the clicked-element's default behaviour
  // (which in many cases could cause a page reload):
  event.preventDefault();

  // using Array.prototype.slice, with Function.prototype.call,
  // on the NodeList returned by document.querySelectorAll(),
  // to create an array of element nodes;
  // 'this.dataset.duplicates' retrieves the attribute-value from
  // the 'data-duplicates' attribute of the clicked element:
  var allCurrent = Array.prototype.slice.call(document.querySelectorAll(this.dataset.duplicates), 0),
    // getting the last element from the array of nodes:
    toClone = allCurrent[allCurrent.length - 1],

    // cloning that node, including its child elements:
    clone = toClone.cloneNode(true),

    // creating a RegExp (regular expression) literal,
    // to match a sequence of one, or more, numbers (\d+)
    // followed by the end of the string ($):
    reg = /\d+$/,

    // creating an 'empty'/unitialised variable for use
    // within the (later) loop:
    childElems;

  // adding the created clone to the allCurrent array:
  allCurrent.push(clone);

  // using Array.prototype.forEach() to iterate over the
  // array, the arguments (names are user-defined):
  // - first (here 'fieldset') is the current array element
  //   over which we're iterating,
  // - second (here 'index') is the index of the current
  //   array element in the array:
  allCurrent.forEach(function(fieldset, index) {

    // finding all descendant elements contained within
    // the current array-element that have a 'name' attribute,
    // using a CSS attribute-selector within
    // document.querySelectorAll():
    childElems = fieldset.querySelectorAll('[name]');

    // iterating over those descendant elements in the
    // array-like NodeList:
    Array.prototype.forEach.call(childElems, function(elem) {

      // if the regular expression matches the name (
      // RegExp.prototype.test() returning a Boolean true/false
      // based on the string matching, or not matching, the
      // regular expression) we replace that match with the index
      // (from the outer loop), or if not we simply append the
      // index to the current name property-value:
      elem.name = reg.test(elem.name) ? elem.name.replace(reg, index) : elem.name + index;
    });

    // navigating from the cloned node to its parent and, using
    // Node.insertBefore(), we insert the created clone before
    // the nextSibling of that cloned node:
    toClone.parentNode.insertBefore(clone, toClone.nextSibling);
  });

}

// getting a reference to the element that should trigger
// the duplication:
var addMore = document.getElementById('duplicate');

// adding an event-handler for the 'click' event
// (note the lack of parentheses):
addMore.addEventListener('click', duplicate)

 function duplicate(event) { event.preventDefault(); var allCurrent = Array.prototype.slice.call(document.querySelectorAll(this.dataset.duplicates), 0), toClone = allCurrent[allCurrent.length - 1], clone = toClone.cloneNode(true), reg = /\\d+$/, childElems; allCurrent.push(clone); allCurrent.forEach(function(fieldset, index) { childElems = fieldset.querySelectorAll('[name]'); Array.prototype.forEach.call(childElems, function(elem) { elem.name = reg.test(elem.name) ? elem.name.replace(reg, index) : elem.name + index; }); toClone.parentNode.insertBefore(clone, toClone.nextSibling); }); } var addMore = document.getElementById('duplicate'); addMore.addEventListener('click', duplicate) 
 label { display: block; } 
 <!-- here we're using an actual <form> element --> <form action="#" method="post"> <!-- using a fieldset to group the related fields together --> <fieldset class="clinicalInformation"> <!-- the <legend> element semantically titles that group of related fields --> <legend class="form-title"> Clinical Information </legend> <!-- the <label> semantically associates a text-label with a specific form-element; that form-element (<input />, <textarea>, <select>) can appear within the <label>, or the <label> can have a 'for' attribute equal to the 'id' of the associated element. --> <label class="form-title">Time Assesed: <input class="form-field" type="time" name="timeassessd" /> </label> <label class="form-title">Blood Pressure: <input class="form-field" type="text" name="bp" /> </label> <label class="form-title">Pulse: <input class="form-field" type="date" name="pulse" /> </label> <label class="form-title">Resp. Rate: <input class="form-field" type="text" name="breathing" /> </label> <label class="form-title">Temp: <input class="form-field" type="text" name="temp" /> </label> <label class="form-title">SPO<sub>2</sub>: <input class="form-field" type="text" name="spo2" /> </label> <label class="form-title">GCS: <input class="form-field" type="text" name="gcs" /> </label> <label class="form-title">AVPU: <input class="form-field" type="text" name="avpu" /> </label> </fieldset> <fieldset> <button id="duplicate" data-duplicates=".clinicalInformation">Add more</button> </fieldset> </form> 

Using jQuery, however, since you've used that tag for your question:

// binding an anonymous click event-handler, using on():
$('#duplicate').on('click', function(event) {
  // preventing the default action:
  event.preventDefault();

  // finding all elements that match the selector from
  // the clicked-element's 'data-duplicates' attribute:
  var allCurrent = $(this.dataset.duplicates),

    // finding the last of those elements:
    toClone = allCurrent.last(),

    // creating the clone, including the child elements:
    clone = toClone.clone(true),

    // the regular expression (as above):
    reg = /\d+$/;

  // adding the clone to the 'allCurrent' collection,
  // then iterating over them with each(), getting a
  // reference to the index of each element in the collection:
  allCurrent.add(clone).each(function(index) {

    // finding all descendant elements that have a name attribute,
    // updating the 'name' property of each of those found
    // elements using prop():
    $(this).find('[name]').prop('name', function(i, n) {
      // the first argument (here: 'i') is the index of the
      // current element in the collection,
      // the second (here: 'n') is the current value of the
      // current element's property.

      // exactly the same as above:
      return reg.test(n) ? n.replace(reg, index) : n + index;
    });
  });

  // inserting the clone into the document
  // after the toClone element:
  clone.insertAfter(toClone);
});

 $('#duplicate').on('click', function(event) { event.preventDefault(); var allCurrent = $(this.dataset.duplicates), toClone = allCurrent.last(), clone = toClone.clone(true), reg = /\\d+$/; allCurrent.add(clone).each(function(index) { $(this).find('[name]').prop('name', function(i, n) { return reg.test(n) ? n.replace(reg, index) : n + index; }); }); clone.insertAfter(toClone); }); 
 label { display: block; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <form action="#" method="post"> <fieldset class="clinicalInformation"> <legend class="form-title"> Clinical Information </legend> <label class="form-title">Time Assesed: <input class="form-field" type="time" name="timeassessd" /> </label> <label class="form-title">Blood Pressure: <input class="form-field" type="text" name="bp" /> </label> <label class="form-title">Pulse: <input class="form-field" type="date" name="pulse" /> </label> <label class="form-title">Resp. Rate: <input class="form-field" type="text" name="breathing" /> </label> <label class="form-title">Temp: <input class="form-field" type="text" name="temp" /> </label> <label class="form-title">SPO<sub>2</sub>: <input class="form-field" type="text" name="spo2" /> </label> <label class="form-title">GCS: <input class="form-field" type="text" name="gcs" /> </label> <label class="form-title">AVPU: <input class="form-field" type="text" name="avpu" /> </label> </fieldset> <fieldset> <button id="duplicate" data-duplicates=".clinicalInformation">Add more</button> </fieldset> </form> 

References:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM