Laravel Livewire - Dynamic Progress Text

October 4th, 2021

Problem

During a recent project, I was using Laravel Livewire to install a composer package from the dashboard. The user entered the full package name (with optional version), and then I sent off a job that could run in the background and install it.

The problem I encountered was that I wanted to use Livewire to display live text updates about the current step the installation process was on. However, due to how Livewire works the below doesn't work.

1<div>{{ $message }}</div>
2<button wire:click="install()">Install Package</button>
1public string $message = '';
2 
3public function install() {
4 $this->message = 'Starting install...';
5 
6 InstallPackage::dispatch();
7 
8 $this->message = 'Running install as background process...';
9}

The first message Starting install.. never shows, as only one request is sent only the last message is seen.

Solution

In order to get this to work, we are going to have to manipulate the cache and Livewire's polling functionality.

1<div wire:poll.500ms="updateMessage()">
2 {{ $message }}
3</div>

In the above we are going to hit the updateMessage function every 500 milliseconds and refresh the message text. The function will pull the message from the cache.

1public function updateMessage() {
2 $this->message = cache()->get('installMessage') ?? '';
3}

As a side note the below will NOT work, due to how the requests are sent for the action and polling:

1public function setCacheMessage() {
2 cache()->put('installMessage', '1');
3 
4 sleep(2);
5 
6 cache()->put('installMessage', '2');
7}

Instead, we can set an initial message and then set any updates to that message in the background job.

1// Livewire Component
2// Within the component we want to set the initial message,
3// then dispatch the job.
4public function runInstall() {
5 cache()->put('installMessage', 'Starting install...');
 6 
7 InstallPackage::dispatch();
 8}
 9 
10// Job
11// Within the job we update the message, then run the rest
12// of the function. Potentially a sleep(1) could be added
13// to ensure the first message is seen. Once done, we can
14// remove the message from the cache so it disappears from
15// the install screen.
16//
17// In the failed method we update the message and set a time
18// of 5 seconds, so it'll show the message initially and then
19// be removed.
20public function handle() {
21 cache()->put('installMessage', 'Running install as background process...');
22 
23 // rest of function...
24 // sleep(1);
25 
26 cache()->forget('installMessage');
27}
28 
29public function failed() {
30 cache()->put('installMessage', 'Failed to install package', 5);
31}