I'm trying to create a way to dynamically load Livewire nested components by having a main container component like this:
ComponentContainer.php
class ComponentContainer extends Component
{
public $component = 'active';
protected $listeners = [
'switch'
];
public function switch(string $component)
{
$this->component = $component;
}
public function render()
{
return view('livewire.component-container', [
'component' => $this->component,
'key' => random_int(PHP_INT_MIN, PHP_INT_MAX),
]);
}
}
component-container.blade.php
<div>
<h1>Component Container</h1>
@livewire($component, key($key))
<button wire:click="$emit('switch', 'active')">
{{ __('Active') }}
</button>
<button wire:click="$emit('switch', 'expired')">
{{ __('Expired') }}
</button>
</div>
It's working insomuch as when I click "active" or "expired" it's loading one of these components:
Active.php
class Active extends Component
{
public function render()
{
return view('livewire.active');
}
}
active.blade.php
<div>
active
</div>
Expired.php
class Expired extends Component
{
public function render()
{
return view('livewire.expired');
}
}
expired.blade.php
<div>
expired
</div>
But I get the following error in the console log, and I don't understand why:
Livewire: Multiple root elements detected. This is not supported. See docs for more information https://laravel-livewire.com/docs/2.x/troubleshooting#root-element-issues <div wire:id="jdHgW7KzB3wWUCl7vMI4">expired
Doesn't seem to make sense as it's clearly just one root element. Interestingly it doesn't do it on the first load, regardless of whether I set $component
to active
or expired
The error is being caused by the final HTML comment (wire:end) being missing. For some reason, this only happens if the buttons are placed after the dynamic component call....
This displays the "multiple root elements detected" error
<div>
<h1>Component Container</h1>
@livewire($component, key($key))
<button wire:click="$emit('switch', 'active')">
{{ __('Active') }}
</button>
<button wire:click="$emit('switch', 'expired')">
{{ __('Expired') }}
</button>
</div>
But this works fine...
<div>
<h1>Component Container</h1>
<button wire:click="$emit('switch', 'active')">
{{ __('Active') }}
</button>
<button wire:click="$emit('switch', 'expired')">
{{ __('Expired') }}
</button>
@livewire($component, key($key))
</div>
I'm not sure if this is expected behaviour or if it's a bug, but this fixes the issue described.