0

Quick backstory. I have a portion of a simple form that allows the user to add/remove a row of three inputs. I'd thought originally that I would just use jQuery to show/hide static fields, but I poked around and found a solution that seemed to work really well.

(Reference: http://www.sanwebe.com/2013/03/addremove-input-fields-dynamically-with-jquery/comment-page-1#comment-6093)

As far as the array is concerned, I was working from this: Submitting a multidimensional array via POST with php

HTML

<div class="multi-field-wrapper">
    <div class="multi-fields">
        <div class="multi-field">
            <button type="button" class="remove-field" title="Remove Product">&times;</button>
            <input type="text" name="part[][number]" class="part-number-input" placeholder="">
            <input type="number" name="part[][quantity]" placeholder="">                                                    
            <input type="number" name="part[][tolerance]" class="" placeholder="">
        </div>
    </div>
    <button type="button" class="add-field" title="Add Product">+</button>
</div>

PHP

if(isset($_POST['part']))
{
    $message .='<table>';
    $message .='<tr><td><b>Part #</b></td><td><b>Quantity</b></td><td><b>Tolerance</b></td></tr>';
    foreach ($_POST['part'] as $parts)
    {
        $message .='<tr>';
        $message .='<td> '.$parts['number'].' </td>';
        $message .='<td> '.$parts['quantity'].' </td>';
        $message .='<td> '.$parts['tolerance'].' </td>';
        $message .='</tr>';
    }
    $message .='</table>';
}

OUTPUT TO EMAIL

Part #   Quantity   Tolerance
part1#
         part1qty
                    part1tol
part2#
         part2qty
                    part2tol

I've only ever messed with extremely simple forms, so any help would be greatly appreciated!

UPDATE: Adding the jQ that clones the fields.

JS

$('.multi-field-wrapper').each(function() {
    var $wrapper = $('.multi-fields', this);
    $(".add-field", $(this)).click(function(e) {
        $('.multi-field:first-child', $wrapper).clone(true).fadeIn(300).appendTo($wrapper).find('input').val('').focus();
    });
    $('.multi-field .remove-field', $wrapper).click(function() {
        if ($('.multi-field', $wrapper).length > 1)
            $(this).parent('.multi-field').remove();
    });
});

Again, I really appreciate the help.

Community
  • 1
  • 1
Todd
  • 190
  • 2
  • 14

3 Answers3

3

Generally speaking, the array[] syntax makes an assignment to a new index in the array. In other words, if you don't specify an index, it will create one for you.

What's happening in your code is that you're assigning a new index to your array every time. For example,

part[][number]    => part[0][number]
part[][quantity]  => part[1][quantity]
part[][tolerance] => part[2][tolerance]

The quick solution to your problem is specifying the index instead of creating a new one. For example,

<input type="text" name="part[0][number]">
<input type="number" name="part[0][quantity]">                                                    
<input type="number" name="part[0][tolerance]">

<input type="text" name="part[1][number]">
<input type="number" name="part[1][quantity]">                                                    
<input type="number" name="part[1][tolerance]">

Depending on what you're trying to do, it may be easier to submit JSON data instead of multi-dimensional form data. Particularly if this is being generated through javascript anyway.

majidarif
  • 18,694
  • 16
  • 88
  • 133
  • I see. I'll update my question, but what I'm trying to do is allow the visitor to add/remove a row of three inputs. I then want to pass that information along in the form of an email. – Todd Mar 14 '14 at 18:47
1

Here the problem is that you are not specifying the first index in the multidimensional array, so PHP has not way to tie the items together.

What you are getting is something like this:

Array(
    0 => Array(
        'number' => ...
    ),
    1 => Array(
        'quantity' = > ...
    ),
    2 => Array(
        'tolerance' = > ...
    ),
    3 => Array(
        'number' => ...
    ),
    4 => Array(
        'quantity' = > ...
    ),
    5 => Array(
        'tolerance' = > ...
    ),
    ...
)

You see you get a new element in the outer array each time you set an inner array value.

You need to change your markup to something like:

<input type="text" name="part[0][number]">
<input type="number" name="part[0][quantity]">                                                    
<input type="number" name="part[0][tolerance]">

<input type="text" name="part[1][number]">
<input type="number" name="part[1][quantity]">                                                    
<input type="number" name="part[1][tolerance]">

This will ensure the inner array items are grouped to the proper outer array positions.

Mike Brant
  • 70,514
  • 10
  • 99
  • 103
  • I had a feeling that this is what was going on. Unfortunately, I don't think that I can actually denote the numbering scheme like you have it, as the fields are dynamically generated. – Todd Mar 14 '14 at 18:49
  • @twf1985 Sure you can. If you are adding the fields via javascript, you can set the field names via javascript as well. At a very simple level, you could simply increment a javascript variable which determines the next index number to apply. – Mike Brant Mar 14 '14 at 18:55
  • I don't think so. Here's the fiddle I initially worked off of: http://jsfiddle.net/aaki/hMJEy/1/ – Todd Mar 14 '14 at 18:57
  • @twf1985 that fiddle is basically irrelevent, as it is dealing with a single dimension in the array, so there is no need to force an index. You could easily declare a javascript variable in global context like `var nextInputIndex = 1`, use the value in `name` attribute when creating a new set of fields, and then increment the value. Very straightforward. – Mike Brant Mar 14 '14 at 19:02
  • I understand what you're saying, but I'm not very adept with using JS, either. The fiddle I showed you uses clone() to duplicate the desired div, instead of explicitly dictating through javascript what to duplicate. I didn't realize that the problem could be JS based, so I updated the question with more of the code I'm using. How would you change it? Thank you! – Todd Mar 15 '14 at 03:02
0

Thanks to those who helped me identify the issue.

Here's how I fixed my particular problem. It's probably not the most beautiful of solutions, but I didn't want to complicate the JS I was using to duplicate this array.

First I changed the HTML:

<input type="text" name="part_number[]" class="part-number-input">
<input type="number" name="quantity[]">                                                    
<input type="number" name="tolerance[]">

Then the problem was getting it to come out right on the other end. Following the solution from this question, How to get form input array into PHP array, I amended my PHP:

$part_number = $_POST['part_number'];
$quantity = $_POST['quantity'];
$tolerance = $_POST['tolerance'];

if(isset($_POST['part_number']))
{
    $message .='<table>';
    $message .='<tr><td><b>Part #</b></td><td><b>Quantity</b></td><td><b>Tolerance</b></td></tr>';
    foreach ( $part_number as $key => $part)
    {
        $message .='<tr>';
        $message .='<td> '.$part.' </td>';
        $message .='<td> '.$quantity[$key].' </td>';
        $message .='<td> '.$tolerance[$key].' </td>';
        $message .='</tr>';         
    }
    $message .='</table>';
}

Works exactly the way I intended it to. I'm sure if spent the time doing something like this, How to add (clone) form fields using jQuery and increment ids and names, I could have kept my PHP the way it was. I just didn't want to spoil the simplicity of the JS I already had that functioned well.

Thanks again!

Community
  • 1
  • 1
Todd
  • 190
  • 2
  • 14