Problem
When building a website with LiveWire you may want a file upload preview, an image carousel, or other things that are best done client-side. There’s a number of challenges when first setting up client-side rendering with LiveWire. How do we access and update PHP data? And can we listen for changes in that data? What if we only want part of our component to be handled client-side?
Solution
Alpine is a lightweight tool for adding a touch of client-side rendering to your app. It has attributes and properties that allow you to access, update, and listen for LiveWire PHP data.
Example: Component to show latency
As an example let’s build a LiveWire component that shows the latency (i.e. ping time) between the browser and server when a user clicks a button. To do this we’ll need to store the start time on the client, send a request to the server, then subtract the start time from the current time when the server responds.
What we will be building
First we’ll need to add Alpine’s script file to our project.
<head>
...
<script src="https://cdn.jsdelivr.net/gh/alpinejs/[email protected]/dist/alpine.min.js" defer></script>
</head>
Let’s start out with a basic LiveWire component that has a property that stores the latency
and a method that can toggle the showLatency
property.
public $latency = 0;
public $showLatency = false;
public function toggle() {
$this->showLatency = !$this->showLatency;
}
public function render()
{
return view('livewire.ping');
}
Our template file also looks pretty standard:
<button type="button" wire:click="toggle">
{{ $showLatency ? "Stop Ping" : "Start Ping" }}
</button>
<!-- We need to hide/show this based on $showLatency -->
<div>
<!-- Latency will be shown here -->
<h1></h1>
</div>
Now comes the Alpine client-side magic. The main way to use Alpine is through attributes and properties. Attributes are put inside HTML tags and are used to store state, decide whether the component should be displayed, what text should be in the component, and 12 other things.
<div x-data="{ latency: 0, showLatency: false }" x-show="showLatency">
<h1 x-text="latency + 'ms'"></h1>
</div>
The x-data
attribute allows us to store state such as the latency
and showLatency
variables. We can use these variables in other attributes, x-show
causes the component
to only be shown when showLatency
is true. The x-text
attribute inserts the variable
as text, in this case it would show 0ms
. But wait! This isn’t using the state from
LiveWire, it’s creating its own. To share state between Alpine and LiveWire we can use
the feature @entangle
.
<div x-data="{ latency: @entangle('latency'), showLatency: @entangle('showLatency') }" x-show="showLatency">
<h1 x-text="latency + 'ms'"></h1>
</div>
The @entangle
feature means that when the value is changed on the client or server,
it is updated on the other side. Now when we click the show button, the latency value
will be displayed. We still need to calculate and update the latency. To do this
we will use Alpine properties to generate and set the latency.
First let’s lay the groundwork by adding a method called ping
to our LiveWire
component. When called it returns a pong
event with the start time value it was passed.
public function ping($start)
{
$this->emit('pong', $start);
}
Now in our template we add the x-init
attribute that runs when the component
is rendered. We listen for the pong
event and set the latency
variable
to be the start time subtracted from the current time. Finally, we have a
setInterval
that calls the ping
method every second. Interaction
with the server is done through the $wire
property. It gives
us access to everything inside the LiveWire component through its various methods.
<div ... x-init="
$wire.on('pong', (start) => $wire.set('latency', Date.now() - start));
setInterval(() => $wire.ping(Date.now()), 1000);
">
<h1 x-text="latency + 'ms'"></h1>
</div>
There we have it! A client-side rendered component that shares server-side state. What we built displays the latency between the browser and server. It can even be toggled between hidden and shown.
Discussion
LiveWire has great support for Alpine. It’s easy to add to a project, and you can just use it when needed. If you’re making a modal, a dropdown, a file preview, or anything else that can be done with simple client-side rendering, Alpine is a great solution.