0

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!

3
  • Why do you have all your names for your fields as arrays? Commented Nov 7, 2016 at 12:43
  • @iLLin - what would be my alternative in this situation? Commented Nov 7, 2016 at 16:40
  • Why did this question receive a down vote? Commented Nov 8, 2016 at 10:13

2 Answers 2

2

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'])) {
        ...
    }
}
Sign up to request clarification or add additional context in comments.

3 Comments

In some cases the user will be adding new details while making changes to the privacy setting on existing details. As such I won't always have access to $detail->id so I like your first solution. That has changed the behaviour... whenever a detail is set to be private it, it is always the next detail in the loop that has the setting applied to it.
I was actually wrong. You cannot use hidden input trick together with [] in input names, because these extra fields would be appended to the form no matter what the value of checkbox is. I updated the answer.
Thanks Paul. Your answer at least set me on the right track to a rather hacky solution. As I'm relying on javascript anyway I simply used it to disable the hidden field whenever the checkbox was checked - so only one privacy value was stored in each iteration of the loop. It works a treat for now, although I think I'll need to rewrite that portion of the controller logic entirely at some point.
0

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>

1 Comment

Thanks. Just to clarify, the issue is that the value is being stored to the wrong row in the database.

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.