5

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();
    }
}
5
  • What class type is Multiple? Laravel's Model class doesn't have a saveMany() method. Commented Jul 25, 2015 at 17:25
  • Thats my own class, this is just a testing repo (testing multiple row saves, hence the name). saveMany() is my mistake, but I can't even get to that part Commented Jul 25, 2015 at 17:26
  • With regards to saveMany(), whats this? laravel.com/docs/5.1/… Commented Jul 25, 2015 at 17:34
  • 1
    That's the saveMany() method on the HasOneOrMany or BelongsToMany classes, not on the model itself. If you've setup a HasMany or BelongsToMany relationship on your model, you can use it like $myModel->myRelationship()->saveMany($arrayOfRelatedModels). Commented Jul 25, 2015 at 17:46
  • Cool - I'll bear that in mind. However I still can't get my original question working :/ Commented Jul 25, 2015 at 17:51

3 Answers 3

9

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, I'll check when I'm back at my computer tomorrow. That does make sense. It sounds like I need a count in jquery for each (pair) input. I'll let you know either way.
This has worked (although I added the count numbers in manually in Dev Tools), but it did save all entries successfully. Now I just need to figure out how to build in a count :)
3

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

Comments

0

I agree that this is a problem with your element names, but disagree with Ben's solution. You can keep your JavaScript as-is and handle this in PHP:

public function store()
{
    $rows = Input::get('rows');

    $userId = Auth::id();
    for ($i = 0; $i < (count($rows) - 1); $i += 2) {
        $item = new Multiple([
            'user_id' => $userId,
            'link'    => $rows[$i]['link'],
            'store'   => $rows[$i + 1]['store'],
        ]);
        $item->save();
    }
}

1 Comment

Thanks for your response, I was hoping this would work (as it does seem cleaner) over the jQuery fix, but I get the same error "Undefined index: link" and the top answer has worked.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.