Laravel Livewire is a "full-stack framework for Laravel that makes building dynamic interfaces simple, without leaving the comfort of Laravel." You might be used to using frameworks such as Vue.js, React, or another JavaScript framework to manage your front-end data in Laravel, but with Livewire, gone are the days of having to make AJAX requests to your own API to re-render data in the browser. In short, and from personal experience, Livewire will decrease your development time significantly by coupling your front-end with the back-end; it eliminates the need to manage most dependencies with webpack or ingesting your own API.
Before you begin this tutorial, make sure you have the following set up/installed:
A Twilio Account (Sign up with this link and receive an additional $10 credit.)
A Twilio phone number
Composer globally installed
A Laravel application already installed
What better way to demonstrate the power of Twilio and Laravel Livewire than by building an in-dashboard phone dialer! We’ll start with some styling to make the phone pad, and then I’ll show you how to “wire” it up with Livewire!
Lately, I’ve been choosing Tailwind CSS for all of my CSS needs as it has an easy to use API. Adding Tailwind CSS to a Laravel project is as easy as pulling it in from their CDN. I’ve spun up a new Laravel project for this example. Let’s jump in!
Run the following command in your terminal to install the package. Make sure that you are in the root of your project directory:
$ composer require livewire/livewire
You will need to add the Livewire JavaScript includes on every page you want to use Livewire. Make a new layout file views/layouts/app.blade.php
to house the Tailwind CSS and add the following code.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Twilio Livewire</title>
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet">
@livewireStyles
</head>
<body class="h-screen w-screen flex items-center justify-center">
@yield('content')
@livewireScripts
</body>
</html>
Next, run the following command in your terminal to generate a Livewire component:
$ php artisan make:livewire dialer
This command created two files app/Http/Livewire/Dialer.php
and resources/views/livewire/dialer.blade.php
. Every Livewire class must contain at least the render()
method which tells your app which view to load. The Artisan command has already generated this method for you.
If you’re familiar with Laravel, you can think of Livewire components like Blade includes, allowing you to insert @livewire
anywhere in a Blade view to render the component.
app.blade.php
inside of your layouts
directory and use the @yield(‘content’)
Blade directive no further action is necessary to tell Laravel to render this layout for a Livewire component.Add the following Livewire route to your routes/web.php
to render the component for the /dialer
route:
Route::livewire('dialer', 'dialer');
If your application isn’t running, start it now by running php artisan serve
in your terminal.
Open your web browser and navigate to the /dialer
route at http://127.0.0.1:8000/dialer. Your dialer
component will render with empty content as nothing has been defined yet.
<div class="max-w-lg rounded-lg shadow-lg p-5">
<div class="text-4xl text-center tracking-wider text-gray-600 py-10">
{{$phone_number}}
</div>
<div class="grid grid-cols-3 gap-4">
<button wire:click="addNumber('1')" class="bg-gray-300 text-2xl px-10 py-3 rounded-lg hover:bg-gray-700 hover:text-white transition-all duration-700">1</button>
<button wire:click="addNumber('2')" class="bg-gray-300 text-2xl px-10 py-3 rounded-lg hover:bg-gray-700 hover:text-white transition-all duration-700">2</button>
<button wire:click="addNumber('3')" class="bg-gray-300 text-2xl px-10 py-3 rounded-lg hover:bg-gray-700 hover:text-white transition-all duration-700">3</button>
<button wire:click="addNumber('4')" class="bg-gray-300 text-2xl px-10 py-3 rounded-lg hover:bg-gray-700 hover:text-white transition-all duration-700">4</button>
<button wire:click="addNumber('5')" class="bg-gray-300 text-2xl px-10 py-3 rounded-lg hover:bg-gray-700 hover:text-white transition-all duration-700">5</button>
<button wire:click="addNumber('6')" class="bg-gray-300 text-2xl px-10 py-3 rounded-lg hover:bg-gray-700 hover:text-white transition-all duration-700">6</button>
<button wire:click="addNumber('7')" class="bg-gray-300 text-2xl px-10 py-3 rounded-lg hover:bg-gray-700 hover:text-white transition-all duration-700">7</button>
<button wire:click="addNumber('8')" class="bg-gray-300 text-2xl px-10 py-3 rounded-lg hover:bg-gray-700 hover:text-white transition-all duration-700">8</button>
<button wire:click="addNumber('9')" class="bg-gray-300 text-2xl px-10 py-3 rounded-lg hover:bg-gray-700 hover:text-white transition-all duration-700">9</button>
<button wire:click="addNumber('0')" class="col-span-3 bg-gray-300 text-2xl px-10 py-3 rounded-lg hover:bg-gray-700 hover:text-white transition-all duration-700">0</button>
</div>
<div class="mt-4">
<button class="w-full bg-green-500 py-3 text-white text-2xl uppercase font-black rounded-lg hover:bg-green-600 transition-all duration-700">Call</button>
</div>
</div>
Before this component can be rendered in your browser, you will need to open app/Http/Livewire/Dialer.php
and add a public property
.
<?php
namespace App\Http\Livewire;
use Livewire\Component;
class Dialer extends Component
{
public $phone_number = '';
public function render()
{
return view('livewire.dialer');
}
}
Your browser should now look something like this when navigating to the /dialer
route.
Let’s add a function to handle the button clicks:
public function addNumber($number)
{
if(strlen($this->phone_number) <= 10){
$this->phone_number .= $number;
}
}
A closer look at the dialer.blade.php
will show that we added a wire:click
callback to each button. The value of each button passes data into the addNumber()
method you just created in your Livewire component. Refresh your browser and test it out:
You’re almost ready to place a call. Before that can be done, your application needs to connect to your Twilio account. Begin by installing the the Twilio PHP SDK:
$ composer require twilio/sdk
Next, add your Twilio Credentials to the .env
variables for interfacing with the Twilio API:
TWILIO_ACCOUNT_SID=xxxxxxxx
TWILIO_AUTH_TOKEN=xxxxxxxx
TWILIO_NUMBER=xxxxxxxx
Now add a function to handle making the phone call in the Livewire Dialer class. Start with including the necessary namespaces:
use Twilio\Exceptions\ConfigurationException;
use Twilio\Rest\Client;
Lastly, add the makePhoneCall()
method:
public function makePhoneCall()
{
$this->call_button_message = 'Dialing ...';
try {
$client = new Client(
getenv('TWILIO_ACCOUNT_SID'),
getenv('TWILIO_AUTH_TOKEN')
);
try{
$client->calls->create(
$this->phone_number,
getenv('TWILIO_NUMBER'),
array(
"url" => "http://demo.twilio.com/docs/voice.xml")
);
$this->call_button_message = 'Call Connected!';
}catch(\Exception $e){
$this->call_button_message = $e->getMessage();
}
} catch (ConfigurationException $e) {
$this->call_button_message = $e->getMessage();
}
}
This is a simple example to play the default TwiML message for the listener. In the Blade file, change the call button to the following:
<button wire:click="makePhoneCall" class="w-full bg-green-500 py-3 text-white text-2xl uppercase font-black rounded-lg hover:bg-green-600 transition-all duration-700 focus:outline-none">
{{$call_button_message}}
</button>
Also, add another public property
for the $call_button_message
in the Livewire class. This property modifies the label for the call button and its value will change when we successfully send the call:
public $call_button_message = 'Call';
Any live application has to account for user error. The most obvious cases for error comes with typing the incorrect phone number or even needing to make a change. To improve the UX, let’s add a backspace/delete button and a reset button. Also let’s clear out the phone number if the call is successful.
Change the “0” button to the following:
<button wire:click="resetDialer" class="bg-gray-300 text-gray-600 text-2xl px-10 py-3 rounded-lg hover:bg-gray-700 hover:text-white transition-all duration-700 focus:outline-none">Reset</button>
<button wire:click="addNumber('0')" class="text-gray-600 bg-gray-300 text-2xl px-10 py-3 rounded-lg hover:bg-gray-700 hover:text-white transition-all duration-700 focus:outline-none">0</button>
<button wire:click="delete" class="bg-gray-300 text-gray-600 text-2xl px-10 py-3 rounded-lg hover:bg-gray-700 hover:text-white transition-all duration-700 focus:outline-none">Delete</button>
```PHP
And the following methods to the Dialer class to connect the dialpad to Livewire:
```PHP
public function resetDialer()
{
$this->phone_number = '';
}
public function delete()
{
if(strlen($this->phone_number) > 0){
$this->phone_number = substr($this->phone_number, 0, -1);
}
}
If you’d like to extend this logic further, add $this->resetDialer();
after you echo out “Call Connected” in makePhoneCall()
method to remove the phone number after a successful call!
There is a small bit of JavaScript that Livewire uses to make a request to the server when there is a change with a "watched" element. When a change is detected, a roundtrip AJAX request is made to the server that returns the newly rendered DOM as HTML. Once that request is returned, Livewire uses state logic to know which HTML to replace with the new data.
A great example of this implementation being used in an Enterprise application is Github.com. If you navigate through Github with your XHR tab open in the dev console, you can see HTML being returned when actions are taken and substituted in the existing DOM. Genius!
Livewire is capable of handling many more scenarios than DOM replacement such as authorization, validation, flashing messages to the session, redirection, and pagination. Plus it provides several UI enhancements like transitions, polling, listening for loading states and prefetching to name a few. You could extend this application further by ...