views:

52

answers:

3

I'm trynig to come up with a clean and efficient way of handling form input names when dynamically adding more to the POST array.

For example, if I have the following form:

<fieldset>
   <input type="text" name="users-0.firstname" />
   <input type="text" name="users-0.lastname" />
</fieldset>

I then click an 'addmore' button which duplicates that HTML and adds it back into the document. Resulting in:

<fieldset>
   <input type="text" name="users-0.firstname" />
   <input type="text" name="users-0.lastname" />
</fieldset>

I'm trying to find the best way to increment that name index so I can use the data on the server. So far, I've been using the following code:

$('.addmore').click(function()
{
   var $button   = $(this);
   var $fieldset = $button.prev('fieldset');
   var $newset   = $('<div class="new">' + $fieldset[0].innerHTML + '</div>');

   $newset.insertBefore($button);
   updatenames($newset, $('fieldset').length + 1);
});

function updatenames($set, newIndex)
{
   /*
      updates input names in the form of
      set-index.name
      set-index
   */
   var findnametype = function(inputname)
   {
      if (inputname.indexOf('-') != -1 && inputname.indexOf('.') != -1)
      {
         var data1 = inputname.split('-');
         var data2 = data1[1].split('.');

         // [type, set, index]
         return [1, data1[0], parseInt(data2[0])]
      }

      if (inputname.indexOf('-') != -1 && inputname.indexOf('.') == -1)
      {
         var data = inputname.split('-');
         return [2, data[0], data[1]];
      }

      return false;
   };

   var type = findnametype($set.find('input:eq(0)')[0].name);

   $set.find('input, select').each(function()
   {
      var $input   = $(this);

      var oldname  = $input[0].name;
      var newname  = false;

      switch (type[0])
      {
         case 1: newname = oldname.replace('-' + type[2], '-' + newIndex);
            break;
         case 2: newname = oldname.replace('-' + type[2], '-' + newIndex);
            break;
      }

      $input[0].name = newname;
   });

   return type;
}

That updatenames function is a variation of what I've been using lately. In this case, I check to find the format of the input name. I then increment the index.

The incrementing, as you've probably noticed, happens in the DOM. As a 'part 2' to my question, I'd like to learn how to have that object returned for me to then insert into the DOM.

Something like:

$newset = updatenames($newset, $('fieldset').length +1);
$newset.insertBefore($button);

Your help is appreciated. Cheers.

A: 

Have you considered using array-based field names? You wouldn't have to alter those at all:

<input type="text" name="users.firstname[]" />
<input type="text" name="users.lastname[]" />

whether this works for you will of course depend on what you're going to do with the fields.

Pekka
When I'm working with PHP, I use that array method. That particular code was taken from a Pythons project I'm working on which utilizes <a href="http://formencode.org/modules/variabledecode.html">FormEncode</a> to convert the POSTed data to a dictionary/list
steve
A: 
<fieldset>
    <input index=1 var=user prop=firstname />
    <input index=1 var=user prop=lastname />
</fieldset>

<fieldset>
    <input index=2 var=user prop=firstname />
    <input index=2 var=user prop=lastname />
</fieldset>

before you submit your form

get the custom attributes and construct your 'name' attribute

[update]

its jsp but shouldn't be hard for u to convert to php

<%
for (int i = 0; i < 1000; i++) {
%>

<fieldset>
<input index=<%=i%> var=user prop=firstname />
<input index=<%=i%> var=user prop=lastname />
</fieldset>
<%
}
%>

for the js code

$('button').click(function(){

   $('input').each(function(i, node){
      var $node = $(node);

      $node.attr('name', $node.attr('var') + $node.attr('index') + "."+ $node.attr('prop'))

   });

});
Dapeng
If I have a few hundred inputs (on one form, this is the case) performing those changes in the one hit could cause a performance hit on the browser
steve
do you have test data for your performance hit issue? i tested on firefox, there are 2000 input fields inside, took less than 1 sec to update all of them
Dapeng
My comment was an assumption. I hadn't tested it. I'd like to see your code for constructing the name if you wouldn't mind posting it?
steve
A: 
<script type="text/javascript">
    $(document).ready(function () {
        $('.addmore').click(function () {
            var fieldset = $(this).prev('fieldset');
            var newFieldset = fieldset.clone();
            incrementFieldset(newFieldset);
            newFieldset.insertBefore($(this));
        });
    });

    function incrementFieldset(set) {
        $(set).find('input').each(function () {
            var oldName = $(this).attr('name');
            var regex = /^(.*)-([0-9]+)\.(.*)$/;
            var match = regex.exec(oldName);
            var newName = match[1] + '-' + (parseInt(match[2]) + 1) + '.' + match[3];
            $(this).attr('name', newName);
        });
    }
</script>

<fieldset>
   <input type="text" name="users-0.firstname" />
   <input type="text" name="users-0.lastname" />
</fieldset>
<input type="button" class="addmore" value="Add" />
Sjoerd