Joe Spurling
Joe Spurling

Reputation: 977

Looping through input array in Laravel 5

I have a basic UI where users can add a simple list with a label and a value. I want to loop through that list to store the data in a "Detail" model.

I have the following code.

Controller:

$details = $request->input('detail_label');

foreach($details as $key => $value)
{
    if(!empty($request->input('detail_value.'.$key))) {

        // if the detail has an existing ID
        if($request->input('detail_id.'.$key)) {
            $detail = Detail::find($request->input('detail_id.'.$key));
        } else {
            $detail = new Detail;
        }

        $detail->type = $request->input('detail_type.'.$key);
        $detail->label = $request->input('detail_label.'.$key);
        $detail->value = $request->input('detail_value.'.$key);

        if($request->input('detail_privacy.'.$key) == 1) {
            $detail->privacy = 1;
        } else {
            $detail->privacy = 0;
        }

        $user->details()->save($detail);

    }

}

View:

@foreach($user->details as $detail)
    <div class="detail">

        <input type="hidden" name="detail_id[]" value="{{ $detail->id }}">

        <label>Type
        <select name="detail_type[]">
            <option @if($detail->type == '1')selected @endif value="1">Phone</option>
            <option @if($detail->type == '2')selected @endif value="2">Phone (mobile)</option>
            <option @if($detail->type == '3')selected @endif value="3">URL</option>
            <option @if($detail->type == '4')selected @endif value="4">Email</option>
        </select>
        </label>

        <label>Label
        <input type="text" name="detail_label[]" value="{{ $detail->label }}">
        </label>

        <label>Value
        <input type="text" name="detail_value[]" value="{{ $detail->value }}">
        </label>

        <label>Private?
        <input type="checkbox" name="detail_privacy[]" @if($detail->privacy == true) checked @endif value="1">
        </label>

        <label>Delete?
        <input type="checkbox" name="detail_delete[]" value="{{ $detail->id }}">
        </label>

    </div><!-- / detail -->
@endforeach

Every aspect of my code works as I had planned except the detail_privacy field. It sets and unsets the boolean privacy attribute but it pays no attention to which $key I want. It always sets it according to the order in the loop. If I just set one detail to be private it will be first. If I set two, (whichever two), it will be the first and second.

Something is clearly wrong with my logic but I can't tell what.

Any help would be really appreciated. Thanks!

Upvotes: 0

Views: 5025

Answers (2)

Pawel
Pawel

Reputation: 3346

The reason it doesn't work is that non-checked checkboxes are not included in the post data. You may see it by dumping value of $request->input('detail_privacy').

To be able both to edit existing and add new details, you need to set keys on inputs in the form. Anything really, as long as you keep track of it. To make things easier you can add hidden input named same as the checkbox, so detail_privacy will be always present in the post data. For example:

@foreach ($user->details as $key => $detail)
    <input type="hidden" name="detail_id[{{ $key }}]" value="{{ $detail->id }}">
    ...
    <input type="hidden" name="detail_privacy[{{ $key }}]" value="0">
    <input type="checkbox" name="detail_privacy[{{ $key }}]" @if($detail->privacy == true) checked @endif value="1">
    ...
@endforeach

If you add new fields dynamically ie. with javascript you need to respect those keys. Its quite simple though, just pass last value of $key to your js and you're set.

Also I would recommend different notation for input names: details[{{ $key }}][id] instead of detail_id[{{ $key }}]. This way controller action will become much simpler:

foreach ($details as $detail) {
    if (! empty($detail['id'])) {
        ...
    }
}

Upvotes: 2

Poiz
Poiz

Reputation: 7617

If the Boolean values are stored as TINYINTS in the Database (as in: 0 or 1); then perhaps taking out the Boolean true || false may resolve the Issue. Not Certain but guessing it's worth the try:

    <!-- JUST TRY IT LIKE SO:  @if($detail->privacy) checked @endif -->
    <label>Private?
    <input type="checkbox" 
           name="detail_privacy[]" 
           @if($detail->privacy) checked @endif value="1"
    >
    </label>

Or Hypothetically:

    <!-- YOU MAY ALSO USE "1" LIKE SO:  @if($detail->privacy==1) checked @endif -->
    <label>Private?
    <input type="checkbox" 
           name="detail_privacy[]" 
           @if($detail->privacy==1) checked @endif value="1"
    >
    </label>

Upvotes: 0

Related Questions