Shiv Shiv - 22 days ago 7
PHP Question

HTML Array Fields Parsing in PHP

I have a form setup like this:

<form action="/clients/{{ $client->id }}/create-invoice" method="post">
<div class="form-group">
<label for="due_date" class="sr-only">Due Date</label>
<input type="date" name="due_date" class="form-control" placeholder="Due Date">
</div>
<hr />
<p class="clearfix">
<strong class="pull-left">Invoice Items</strong>
<a id="add_invoice_item" class="pull-right"><span class="fa fa-plus"></span></a>
</p>
<div class="form-group invoice_item">
<div class="row">
<div class="col-ms-6 col-sm-8">
<input type="text" name="item_description[]" class="form-control" placeholder="Description">
</div>
<div class="col-ms-3 col-sm-2">
<input type="number" class="form-control" name="item_quantity[]" placeholder="Quantity">
</div>
<div class="col-ms-3 col-sm-2">
<input type="text" class="form-control" name="item_price[]" placeholder="Price">
</div>
</div>
</div>
<div class="form-group">
<input type="hidden" name="_token" value={{ csrf_token() }}>
<button class="btn-primary btn btn-block">Create Invoice</button>
</div>
</form>


I am using Laravel 5.2.

I have the following jQuery to allow the user to add more invoice items:

$("#add_invoice_item").click(function(){
$(".invoice_item").first().clone().insertAfter("div.invoice_item:last").find("input[type='text']").val("");
});


The problem is when I am looking at the request:

public function store(Request $request, Client $client)
{
return $request->all();
}


It returns this:

{
"due_date": "2016-11-19",
"item_description": [
"Website Development",
"SEO",
"Server Setup"
],
"item_quantity": [
"1",
"1",
"1"
],
"item_price": [
"450.00",
"300.00",
"100.00"
],
"_token": "7tUMdXX9FBU4a7cug51oBlrRyeBi9H8ucUNltQgM"
}


And whilst that is the expected result I am not sure how to get it to return in a way which it is easy to use.

For example I need instead of 3 different array lists I need one array list with each object with each field for that row object.

So:

That it would be returning this:

{
"due_date": "2016-11-19",
"items": [
{"description": "Server Setup", "price": "100.00", "quantity": "1"},
{"description": "SEO", "price": "300.00", "quantity": "1"},
{"description": "Website Development", "price": "450.00", "quantity": "1"}
],
"_token": "7tUMdXX9FBU4a7cug51oBlrRyeBi9H8ucUNltQgM"
}


I assume I need to change the HTML and the jQuery but I am unsure how to get it working so that jQuery adds the new fields properly and into the array of
items


Thanks!

Answer

Change naming of your array to product[i][field]

<input type="text" name="product[0][description]"/>
<input type="text" name="product[0][quantity]"/>
<input type="text" name="product[0][price]"/>

<input type="text" name="product[1][description]"/>
<input type="text" name="product[1][quantity]"/>
<input type="text" name="product[1][price]"/>

And in PHP you will receive this:

var_dump($_POST['product']);

[
    [
        'description': 'Website development',
        'quantity': '1',
        'price': '450.00'
    ],
    [
        'description': 'SEO',
        'quantity': '1',
        'price': '300.00'
    ],
]

Only disadvantage is that you need to manually set array index.


Using jQuery and template:

var index = 0;

function add() {
  $('.form').append(template('#my-template', {
    i: index
  }));
  index++;
}

function template(selector, params) {
  if (typeof params === 'undefined') {
    params = [];
  }

  var tplEl = $(selector);

  if (tplEl.length) {
    var tpl = $(selector).html();

    $.each(params, function(i, n) {
      tpl = tpl.replace(new RegExp("\\{" + i + "\\}", "g"), function() {
        if (typeof n === 'object') {
          return n.get(0).outerHTML;
        } else {
          return n;
        }
      });
    });

    return $(tpl);
  } else {
    console.error('Template "' + selector + '" not found!');
  }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button onClick="add()">Add more</button>
<hr/>
<div class="form">

</div>
<script type="text/jQuery-tpl" id="my-template">
  <div class="row">
    {i}: 
    <input type="text" name="product[{i}][description]" />
    <input type="text" name="product[{i}][quantity]" />
    <input type="text" name="product[{i}][price]" />
  </div>
</script>