Reputation: 1359
There are 3 livewire components UserIsExpired
, UserIsActive
and UserIsPending
and 3 buttons respective to each component. When a button is clicked, it should replace previous component with its respective component.
<button wire:click="$emit(active)">{{ __('Active') }}</button>
<button wire:click="$emit(pending)">{{ __('Pending') }}</button>
<button wire:click="$emit(expired)">{{ __('Expired') }}</button>
In view
<livewire:user-is-active :active="$active"/>
<livewire:user-is-pending :pending="$pending"/>
<livewire:user-is-expired :expired="$expired"/>
Component example
class UserIsExpired extends Component
{
protected $listeners = ['expired'];
public function render()
{
return <<<'blade'
<div>
{{-- The best athlete wants his opponent at his best. --}}
</div>
blade;
}
}
When Active
button is clicked, it should load UserIsActive
component. Same goes for other two.
I have been looking livewire doc for long, but unable to find how to make it happen. Thanks in advance.
Upvotes: 5
Views: 12068
Reputation: 10210
I would wrap your components
in a component container
and use it to manage the visibility of your other components
.
component-contaoner.blade.php
<div>
<h4>Component Container</h4>
{{-- this is your dynamic component --}}
@livewire($component, key($key))
<button wire:click="$emit('switch', 'active')">
{{ __('Active') }}
</button>
<button wire:click="$emit('switch', 'pending')">
{{ __('Pending') }}
</button>
<button wire:click="$emit('switch', 'expired')">
{{ __('Expired') }}
</button>
</div>
ComponentContainer.php
class ComponentContainer extends Component
{
private $component = '';
protected $listeners = [
'switch'
];
public function switch(string $component)
{
$this->component = $component;
}
public function mount(string $component = 'active')
{
$this->component = $component;
}
public function render()
{
return view('livewire.component-container', [
'component' => $this->component,
// key is required to force a refresh of the container component
'key' => random_int(-999, 999),
]);
}
}
Then you would use the component container
as follows, passing in an optional component
to show initially otherwise it defaults to active
as set in the mount
function.
@livewire('component-container')
You could put the buttons
anywhere you want and use
$emitTo('container-component', 'switch', 'active')
I just put them inside the component-container
for ease.
A nice thing about this approach is there are no if
conditionals to manage and should you add more components
to switch between, all you need to do is add another button
somewhere with the relevant $emit
.
Upvotes: 10
Reputation: 2352
Another way you can take is setting a self property and in blade make the corresponding livewire directive like if/else (assuming all is under full page component and the model binding refer a user model)
<button wire:click="showNested('active')">{{ __('Active') }}</button>
<button wire:click="showNested('pending')">{{ __('Pending') }}</button>
<button wire:click="showNested('expired')">{{ __('Expired') }}</button>
In view
@if($show == 'isActive')
<livewire:user-is-active :active="$active"/>
@elseif($show == 'isPending')
<livewire:user-is-pending :pending="$pending"/>
@elseif($show == 'isExpired')
<livewire:user-is-expired :expired="$expired"/>
@endif
in component
public $active,$pending,$expired;
public $show = '';
public function render()
{
if(!empty($this->show)){
if($this->show == 'active')
$this->active = User::where('status','active')->first();
elseif(....)
//......
}
return view(.....) //......;
}
public function showNested($value)
{
$this->show = $value;
}
Upvotes: 0
Reputation: 1499
One way to solve this is be adding all listeners to each of the components and switch a flag. Here on the example of UserIsExpired
:
class UserIsExpired extends Component
{
public $state = 'invisible';
protected $listeners = [
'active',
'pending',
'expired',
];
public function active()
{
$this->state = 'invisible';
}
public function pending()
{
$this->state = 'invisible';
}
public function expired()
{
$this->state = 'visible';
}
public function render()
{
if ($this->state === 'invisble') {
return '';
}
return <<<'blade'
<div>
{{-- The best athlete wants his opponent at his best. --}}
</div>
blade;
}
}
For the initially visible component you probably want to set the default value for the state
to visible.
Upvotes: 0