How can I have a button to add more form inputs in CFv5?

It's quite common on a form to have one part that repeats several times. If the number of repeats varies then it can be useful to have an 'Add one' button that will add an extra copy of this part of the form. An example might be for a booking form where one booking can be for several people and you want to enter all of their names. This FAQ shows you how to do this when the number of repeats is limited e.g. up to x people.
The example described here was written for a specific case where the is a minimum of one person and a maximum of five and there are inputs for 'name' and 'address'. The code is flexible and can easily be amended for a different number of people, or for different inputs.
This FAQ is based on the earlier CFv4 FAQ and has been updated to use CFv5 HTML and jQuery in place of MooTools.
The form inputs are built using PHP in a Custom Element element in the Designer tab.
<?php
// set the total count
$count = 5;
for ( $i = 1; $i <= $count; $i++ ) {
  // add classes which will let us identify the inputs to hide
  if ( $i == 1 ) {
    $class = 'show_me';
  } else {
    $class = 'hide_me';
  }
  // add the 'Add one' buttons (but not to the last set)
  if ( $i < $count ) {
    $j = $i+1;
    $button = "<div class='form-group gcore-form-row' id='form-row-{$i}'>
    <div class='gcore-input gcore-display-table' id='fin-button{$i}'>
      <input type='button' name='addone_{$j}' id='addone_{$j}' value='Add one' class='add_one form-control A' /></div></div>";
  } else {
    $button = "";
  }
  // add the inputs with a little ChronoForms styling
  echo "
<div class='form-group gcore-form-row {$class}' id='recipient_{$i}' >
  <div class='gcore-subinput-container-wide' id='fitem-name_{$i}'>
    <label for='recipient_{$i}_name' class='control-label gcore-label-left'>Name</label>
    <div class='gcore-input pull-left gcore-sub-input gcore-display-table' id='fin-name_{$i}' >
      <input type='text' name='recipient[{$i}][name]' id='recipient_{$i}_name' class='form-control A' />
    </div>
  </div>
  <div class='gcore-subinput-container-wide' id='fitem-address_{$i}'>
    <label for='recipient_{$i}_address' class='control-label gcore-label-left'>Address</label>
    <div class='gcore-input pull-left gcore-sub-input gcore-display-table' id='fin-address_{$i}' >
      <input type='text' name='recipient[{$i}][address]' id='recipient_{$i}_address' class='form-control A' />
    </div>
  </div>
  {$button}
</div>
  ";
}
?>

The Label box is left empty.
The second part of the code is JavaScript added in a Load JS action in the On Load event of the form:
jQuery(document).ready(function (jQ) {
  // display the next row and hide the last 'Add one' button
  function addOne(id) {
    var button = '#addone_' + id;
    jQ(button).hide();
    var block = '#recipient_' + id;
    jQ(block).show();
  }
  // hide all but the first set
  jQ('div.hide_me').each(function () {
    jQ(this).css('display', 'none');
  });
  // call the addOne function passing the row number
  jQ('input.add_one').each(function () {
    jQ(this).click( function () {
      var id = jQ(this).attr('id').replace('addone_', '');
      addOne(id);
    });
  });
});

Note that in this code substr(7, 1); is used to get the number from the end of the Add One button id. That is addone_3 gives 3. If the maximum is more than 9 then some adjustment will be needed.

The resulting data is returned as a sub array in $form->data['recipient'] and may need further processing before it can be saved or used in an email. Here's an example form the debugger output on the demo form:
[recipient] => Array (
  [1] => Array (
    [name] => Simon
    [address] => 12 High Steet
  )
  [2] => Array (
    [name] => Steven
    [address] => 72 Main Street
  )
  [3] => Array (
    [name] => Sue
    [address] => 4 Back Street
  )
  [4] => Array (
    [name] => Sally
    [address] => 99 ave de l'Opera
  )
  [5] => Array (
    [name] => Sherlock
    [address] => 1278 6th Steet
  )
)