Save multiple rows to database from dynamic forms in Laravel 5

10,454

Solution 1

One problem is in your JavaScript element names:

<input type="hidden" name="rows[][link]" value="' + link + '">
<input type="hidden" name="rows[][store]" value="' + store + '">

This will generate $rows like:

[
    0 => ["link" => "foo"], 
    1 => ["store" => "bar"]
]

But your PHP code expects $rows to be like:

[
    0 => [
        "link" => "foo",
        "store" => "bar"
    ], 
    1 => [
        "link" => "foo",
        "store" => "bar"
    ]
]

One way to generate the expected values is to specify the row keys in your elements:

<input type="hidden" name="rows[0][link]" value="' + link + '">
<input type="hidden" name="rows[0][store]" value="' + store + '">
<input type="hidden" name="rows[1][link]" value="' + link + '">
<input type="hidden" name="rows[1][store]" value="' + store + '">

Obviously this is a bit tricky given the code you've provided, so let me know if you need assistance with that.

Solution 2

If this helps anyone else, this is the jQuery required to work with Ben's correct answer:

var count = 0;

$(document).on('click', '.new-row', function() {

    count++;

    var store = $('#newlink input[name=prestore]').val();
    var link = $('#newlink input[name=prelink]').val();

    if ($('input[name=prestore]').val().length > 2 && $('input[name=prelink]').val().length > 2) {

        $('<li class="not-saved">' +
            '<a href="' + link + '">' + store + '</a>' +
            '<input type="hidden" name="rows[' + count + '][store]" value="' + store + '">' +
            '<input type="hidden" name="rows[' + count + '][link]" value="' + link + '">' +
            '</li>').appendTo('#link-list').hide().fadeIn(280);

        $('input[name=prestore]').val('');
        $('input[name=prelink]').val('');

    } else {

        console.log('At least 3 characters for each field required!');

    }

});

I also added a tiny bit of validation so it wont append empty fields

Share:
10,454
Jack Barham
Author by

Jack Barham

Updated on June 10, 2022

Comments

  • Jack Barham
    Jack Barham almost 2 years

    I'm using jQuery to generate two dynamic fields. Each pair of fields is displayed on the page and can have multiple instances. On submit (not ajax), each pair of fields is saved into the their own table row along with Auth::id().

    There are two forms in the HTML code, both values are entered, user clicks 'Add link' then jQuery creates two hidden fields (these are the ones that get submitted) and data entered appears (appended) visually to #link-list. The original fields become empty and the process can repeat...

    I'm struggling to create an array that is recognised by eloquent to save the data multiple times.

    I get the error 'Undefined index: link' or whichever the second input row is in jQuery.

    Blade/HTML:

    {!! Form::open(['route' => ['multiple.store'], 'method' => 'post', 'role'=> 'form', 'class' => 'form']) !!}
    
        <ul id="link-list">
            <!-- append new rows -->
        </ul>
    
        <div id="newlink" class="form-inline">
            <div class="form-group">
                {!! Form::text('prestore', null, ['placeholder' => 'Store name', 'class' => 'form-control']) !!}
            </div>
            <div class="form-group">
                {!! Form::text('prelink', null, ['placeholder' => 'Link / URL', 'class' => 'form-control']) !!}
            </div>
            <div class="form-group">
                <button class="btn btn-primary submit new-row" type="button">Add store link</button>
            </div>
        </div>
    
        <br/><br/>
    
        {!! Form::submit('Submit rows', ['class' => 'btn btn-success submit']) !!}
    
    {!! Form::close() !!}
    

    jQuery/JavaScript

    $(document).on('click', '.new-row', function() {
        var store = $('#newlink input[name=prestore]').val();
        var link = $('#newlink input[name=prelink]').val();
        console.log(store, link);
        $('<li class="not-saved">' +
                '<a href="'+link+'">'+store+'</a>' +
                '<input type="hidden" name="rows[][link]" value="' + link + '">' +
                '<input type="hidden" name="rows[][store]" value="' + store + '">' +
            '</li>').appendTo('#link-list').hide().fadeIn(280);
        $('input[name=prestore]').val('');
        $('input[name=prelink]').val('');
    });
    

    Controller:

    public function store()
    {
        $input = Input::all();
    
        foreach ($input['rows'] as $row) {
            $items = new Multiple([
                'user_id' => Auth::id(),
                'store' => $row['store'],
                'link' => $row['link'],
            ]);
            $items->save();
        }
    }