4

I have a property called public $items = []. This can have multiple nested arrays, ie: $items.1, $items.2, $items.3 and so on. Each of these sub arrays needs to hold at least two pieces of data.

$items[1]['prop1'] = "value 1";
$items[1]['prop2'] = "value 2";
$items[2]['prop1'] = "value 1";
$items[2]['prop2'] = "value 2";

My issue is that in my view, I have two inputs bound to these sub properties.

I then add a new array entry based on this input. So if the user enters a certain thing in prop1, the array will contain an auto-generated element based on this input.

Now here's the issue. When I change prop1 and capture it within the updatedItems lifecycle hook, it's correct. But when I change prop2, it overwrites prop1 and the array only ever holds one value.

public function updatedItems($value, $nested)
{
    $nestedData = explode(".", $nested);
    // Get the nested property that was changed. this will yield a string formated as "1.prop1" or "2.prop1"
    // Let's pretend that the $value variable says "value 1" and the $nested variable is "1.prop1"
    if ($nestedData[1] == 'prop1') {
        $this->items[$nestedData[0]]["secondary_value"] = 'secondary value';
        // This should yield an items array that looks like this: items[1]['secondary_value'] = 'secondary value'
    }
    if ($nestedData[1] == 'prop2') {
        $this->items[$nestedData[0]]["third_value"] = 'third value';
        // This should yield an items array that looks like this: items[1]['third_value'] = 'secondary value'
    }
}

My expectation is that I would get an items array that looks like this:

$items = [
    "1" =['prop1' => 'value 1', 'secondary_value' => 'secondary value'],
    "2" =['prop2' => 'value 1', 'third_value' => 'third value']
]

But no matter what I do, the items array ONLY holds one value, the most recent one that was changed. So if I change prop1 first, then change prop2, the array will ONLY contain prop2 and it will not append to the array but basically recreate the whole array containing only that value.

I've looked at multiple other questions that suggest adding a $rules property which I have defined but that still doesn't solve the issue. I've even tried setting a session variable but that seems to have the same issue where it gets over written every time. Does livewire use some sort of session system that conflicts with laravels native one? Any help on getting this data to persist so that my array can hold the values of input1 and input2 at the same time would be greatly appreciated.

View

<tr>
    <td colspan="5">
            <select wire:model="items.1.right_eye_brand">
            <option value=""></option>
            @foreach ($sortedItems as $o)
                <option value="{{ $o }}">{{ $o->brand }}</option>
            @endforeach
        </select>
    </td>
</tr>
<tr>
    <td colspan="5">
        <select wire:model="items.1.left_eye_brand">
            <option value=""></option>
            @foreach ($sortedItems as $o)
                <option value="{{ $o }}">{{ $o->brand }}</option>
            @endforeach
        </select>
    </td>
</tr>
7
  • Given your inputs, $nestedData[0] is always equals 1, right? So, your expected array won't be achieved... Commented Jul 4, 2021 at 21:02
  • there is a loop that's going on also, so it won't always be "1", i just did that for example. the main issue is that items.1 will always ONLY hold one property even if it has two associative keys that are trying to be assigned to it. Commented Jul 4, 2021 at 21:08
  • Can you include your component view? Commented Jul 4, 2021 at 21:15
  • yes of course. I've updated my question. You can see that I have two selects each bound to items.1, one pertaining to the right eye, and one pertaining to the left eye. If I change either select, the items.1 array contains ONLY that eye. It never contains both at the same time even though the keys are different. Commented Jul 4, 2021 at 21:21
  • I see. I gonna try to reproduce the error. Commented Jul 4, 2021 at 21:28

2 Answers 2

5

The problem seems to be related to Livewire life cycle.

The problem

So I was able to reproduce the problem using laravelplayground.com. Here:

reproduced error

Short Answer

Don't dump/dd inside updatedItems.

Long Answer

In fact, items is not correct when dumping items updatedItems. But, the items should be correct if you dump inside render method.

I gonna search deeply to understand why it's happening. But I guess there is some kind of merge with the original items and the items used in updatedItems method, and the merge happens update* methods run and before render is called.

I did another example in laravel playground, and it shows up the items content in view component and as you can see the data returned is always correct.

final example

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

2 Comments

Hi, I think I bumped into a similar issue and it is a bit mind-boggling. Have you found a solution to this? Thank you for the research btw!
Yes, it seems I was generating a false error. As mentioned in the answer here, the array was in fact saving, but dumping it was giving me the error described in my question. So if you save the array to the database as opposed to dd(), you should have the expected result.
1

After some debugging I found the main issue was the component was not enclosed around a single tag

eg: in the above case instead of

<tr>
    <td colspan="5">
            <select wire:model="items.1.right_eye_brand">
            <option value=""></option>
            @foreach ($sortedItems as $o)
                <option value="{{ $o }}">{{ $o->brand }}</option>
            @endforeach
        </select>
    </td>
</tr>
<tr>
    <td colspan="5">
        <select wire:model="items.1.left_eye_brand">
            <option value=""></option>
            @foreach ($sortedItems as $o)
                <option value="{{ $o }}">{{ $o->brand }}</option>
            @endforeach
        </select>
    </td>
</tr>

enclosing it in a single tag solved the issue

<div>
    <tr>
        <td colspan="5">
                <select wire:model="items.1.right_eye_brand">
                <option value=""></option>
                @foreach ($sortedItems as $o)
                    <option value="{{ $o }}">{{ $o->brand }}</option>
                @endforeach
            </select>
        </td>
    </tr>
    <tr>
        <td colspan="5">
            <select wire:model="items.1.left_eye_brand">
                <option value=""></option>
                @foreach ($sortedItems as $o)
                    <option value="{{ $o }}">{{ $o->brand }}</option>
                @endforeach
            </select>
        </td>
    </tr>
</div>

Comments

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.