Skip to content
Advertisement

Laravel Livewire not persisting data in array when updating

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>

Advertisement

Answer

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

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement