We help IT Professionals succeed at work.

Seeking example of dynamic adding & deleting form fields using javascript and then parsing using PHP

egoselfaxis
egoselfaxis asked
on
I'm looking for an example on how to add and delete form elements (text input fields) dynamically  using javascript.  

More specifically, .. there would already be 3 form fields on the page

firstname  ___________
lastname ___________
email ______________

The user would then be able to click on an "add more fields" link/button, .. and every time they click on it, .. another 3 text input fields would be displayed underneath the others. Alternately, .. they'd be able to click on a "delete fields" button/link beside a row of fields to delete that row.  The user should be able to add as many additional sets of fields as they want, and to be able to delete any of all of them as needed.

Finally, .. I need to know how to handle these POST values using PHP on the form handler side.  Do I need to keep track of how many form elements were added and then loop through them somehow?  If so, ... how?  Or is it actually a lot simpler than that?

Thanks,
- Yvan



Comment
Watch Question

Top Expert 2011

Commented:
Though you certainly can do the add/removes dynamically, I've found it easier to maintain (and debug) if you set a maximum and build your page that contains the maximum number of rows and use hide/show functionality whenever the user wants to show or hide something.  On the "hide" event, you also want to clear out the data they entered.

Again, this is simply from a maintenance perspective (especially if others will ever be charged with updating your code some time in the future.)

From a "building the solution" perspective, I'd recommend building the form using 3 sets of data and the hide/show I describe above.  This way you have fixed elements you are working with to get your debugging done.  Once you are happy with how it performs this way, then convert it to adding/removing record sets dynamically.

Just my 2 cents... I'm sure someone will post a nice-and-easy "how to do this dynamically" solution for you to use too.
Yes, on your form you would have a hidden field and it's value set to the total number of groups (each of the 3 fields above coulr be

firstname1
lastname1
email1

firstname2
lastname2
email2

etc.  Then in PHP, you would loop round and call the values:

if ( isset($_POST['nogroups']) ) {
  $nogroups= $_POST['nogroups'];
  $j = 0;
  for ($i = 0; $i < $nogroups; $i++) {
    $groupseqno = $i + 1;
    $firstname = $_POST['firstname'.$groupseqno];
    $lastname = $_POST['lastname'.$groupseqno];
    $email = $_POST['email'.$groupseqno];
  }
}

Open in new window


As for actually displaying fields, I don't know how / if you can create fields on the fly like that.  My solution was to allow, i.e., 10 fields, then have a dropdown list at the top where they would choose how many they wanted.  The onchange event of this dropdown then called javascript with the visible/hidden code
the onchange would also update the hidden field.  Sorry i can't show a live demo of this but it's behind a username/password protected section of a site I did
Just found the file, javascript would look sommething like:

function toggle_teams() {
  var selecteditem = document.getElementById("noteams");
 
  for (i = 1; i <= 8; i++) {
    if (i <= selecteditem.value) {
      document.getElementById("g"+i).style.display = "block";
    }
    else {
      document.getElementById("g"+i).style.display = "none";
    }
  }
}


and your html:
<div>
  <label for="noteams">No. Teams:</label>
  <select name="noteams" id="noteams" onchange="toggle_teams()">
    <option value="1" SELECTED>1</option>
    <option value="2">2</option>
    <option value="3">3</option>
    <option value="4">4</option>
    <option value="5">5</option>
    <option value="6">6</option>
    <option value="7">7</option>
    <option value="8">8</option>
    <option value="9">9</option>
    <option value="10">10</option>
  </select>
</div>

<div id="g1" style="margin-bottom: 15px;">
  <div>
    <label for="firstname1">Firstname:</label>
    <input type="text" name="firstname1" id="firstname1" size="30" value=""/> 
  </div>
  <div>
    <label for="lastname1">Lastname:</label>
    <input type="text" name="lastname1" id="lastname1" size="4" value="" /> 
  </div>
  <div>
    <label for="email1">Email:</label>
    <input type="text" name="email1" id="email1" size="4" value="" /> 
  </div>
</div>
<div id="g2" style="margin-bottom: 15px;">
  <div>
    <label for="firstname2">Firstname:</label>
    <input type="text" name="firstname2" id="firstname2" size="30" value=""/> 
  </div>
  <div>
    <label for="lastname2">Lastname:</label>
    <input type="text" name="lastname2" id="lastname2" size="4" value="" /> 
  </div>
  <div>
    <label for="email2">Email:</label>
    <input type="text" name="email2" id="email2" size="4" value="" /> 
  </div>
</div>

Open in new window

Author

Commented:
I've actually opted for a different approach, .. which will seemingly allow for me to have an unlimited number of additional fields (see my attached code / html file).  To see it in action, .. just click on the "+ Add New Campaign" link. (I just modified an example javascript that I found while doing a search).  

There's just 1 thing that I'd like to change about this script.  Right now, .. if you click on any of the dynamically generated rows (ie: <P> elements) ... that row is DELETED, .. which is a huge problem because the form fields disappear before they even can be filled out.  

How can I adapt my javascript so that the only way a row can be deleted would be to click on those "Delete Row" links that I've added?

Thanks,
- Yvan

p.s. sbickerstaff -- thanks for that PHP script by the way.  That's exactly what I was looking for.







<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
  "http://www.w3.org/TR/html4/strict.dtd">
<html xmlns='http://www.w3.org/1999/xhtml' lang='en' xml:lang='en:us'>
  <head>
    <meta http-equiv="Content-type" content="text/html; charset=utf-8">
    <title>Add and Remove Elements</title>	
    <style type="text/css" media="screen">
      body {
        background: #111;
        color: #fff;
        font: 100% georgia,times,serif;
      }
      h1, p {
        font-weight: normal;
        margin: 0;
        padding: 0 0 .5em 0;
      }
      p {
        cursor: pointer;
      }
    </style>	
    <script type="text/javascript">		
	  var i = 1;	  
      var Dom = {
        get: function(el) {
          if (typeof el === 'string') {
            return document.getElementById(el);
          } else {
            return el;
          }
        },
        add: function(el, dest) {
          var el = this.get(el);
          var dest = this.get(dest);
          dest.appendChild(el);
        },
        remove: function(el) {
          var el = this.get(el);
          el.parentNode.removeChild(el);
		  i = document.getElementById('total').value;	
		  --i;
		  document.getElementById('total').value = i;			  
        }
      };	  
      var Event = {
        add: function() {
          if (window.addEventListener) {
            return function(el, type, fn) {
              Dom.get(el).addEventListener(type, fn, false);
            };
          } else if (window.attachEvent) {
            return function(el, type, fn) {
              var f = function() {
                fn.call(Dom.get(el), window.event);
              };
              Dom.get(el).attachEvent('on' + type, f);
            };
          }
        }()
      };	  
      Event.add(window, 'load', function() {        
        Event.add('add-element', 'click', function() {
          var el = document.createElement('p');
          el.innerHTML = 'Campaign Name #' + i + ': <input type="text" name="ppc_campaign_name' + i + '" id="ppc_campaign_name' + i + '" value="" /> &nbsp; AdWords Account #' + i + ': <input type="text" name="ppc_adwords_acct_num' + i + '" id="ppc_adwords_acct_num' + i + '" value="" /> &nbsp; &nbsp; AdCenter Account #' + i + ': <input type="text" name="ppc_adcenter_acct_num' + i + '" id="ppc_adcenter_acct_num' + i + '" value="" /> &nbsp; <a href="#" style="color:red">Delete Row</a>';  	
		  ++i;	
		  document.getElementById('total').value = i;	
          Dom.add(el, 'content');
          Event.add(el, 'click', function(e) {
            Dom.remove(this);
          });
        });
      });
    </script>
  </head>
  <body>
    <div id="doc">
      <h1>Add &amp; Remove Elements with JavaScript</h1>	  
	  <p>Campaign Name #0: <input type="text" name="ppc_campaign_name0" id="ppc_campaign_name0 value="" /> &nbsp; AdWords Account #0: <input type="text" name="ppc_adwords_acct_num0" id="ppc_adwords_acct_num0" value="" /> &nbsp; &nbsp; AdCenter Account #0: <input type="text" name="ppc_adcenter_acct_num0" id="ppc_adcenter_acct_num0" value="" /></p> 
      
      <div id="content"></div>	  
	  <p id="add-element">+ Add New Campaign</p>	  
	  <br />	  
    </div>	
	<br />	
	TOTAL NUMBER OF ROWS = <input type="text" name="total" id="total" value="1" /> 	
</body>
</html>

Open in new window

Also, instead of doing fname1, fname2, etc... you could set all of them to fname[] which tells php this is an array. Each field set will have the same key so:

<?php

// Simplified you should first check they are set before trying to use them
$fnames = $_POST['fname'];
$lnames = $_POST['lname'];
$emails = $_POST['emails'];

results = array();

foreach( $fnames as $k => $fname ) {
   results[] = array(
         'fname' => $fname,
         'lname' => $lnames[$k];
         'email' => $emails[$k];
      );
}

// visualize the gathered results
var_dump($results);

Open in new window


HTH
Sorry, can't understand how that JavaScript code you posted works.