Laravel Livewire Dependent Dropdown

Laravel Livewire Dependent Dropdown

ยท

5 min read

In this tutorial, you will learn how to implement a dependent dropdown using Laravel 8.x and Livewire 2.x

Table of contents

  1. Create new Laravel project
  2. Set up database credentials
  3. Country and City model, migration, and seeder
  4. Install Laravel Livewire
  5. Create Livewire component
  6. CountryDropdown Component
  7. Github Repo

1. Create new Laravel Project.

Create a new Laravel project with this command

composer create-project laravel/laravel Laravel-Livewire-Dependent-Dropdown

2. Set up database credentials

You need to configure your credentials in the .env file. database_credentials.png

3. Country and City model, migration, and seeder.

In this step, we need to create two models one for countries and the other for cities, to do that execute the following command

php artisan make:model Country -ms
php artisan make:model City -ms

Note: the flag -ms means migration (m), seeder (s)

Great!!!. Now we can configure our migrations. Let's go to the migrations folder. Locate in app/database/migrations/ and first we need to edit Country migration

 public function up()
    {
        Schema::create('countries', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->timestamps();
        });
    }

Now, it's the turn to edit the City migration

  public function up()
    {
        Schema::create('cities', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->foreignId('country_id')->nullable()->constrained();
            $table->timestamps();
        });
    }

Ok, everything looks good, it's time to edit the models. Let's go to app/Models/Country.php and add this line.

protected $fillable = ['name'];

At this moment, we have to edit the City model.

protected $fillable = [
        'name',
        'country_id'
    ];

That's it, just edit each seeder, firstly we need to search the country seeder located at app/database/seeders/CountrySeeder.php and add this code

public function run()
    {
        $countries = [
            [
                'name' => 'Canada'
            ],
            [
                'name' => 'Italy'
            ]
        ];

        foreach ($countries as $country) {
            Country::create($country);
        }
    }

We can edit the app/database/seeders/CitySeeder.php file adding this code

   public function run()
    {
        $cities = [
            [
                'name' => 'Toronto',
                'country_id' => 1 //Canada
            ],
            [
                'name' => 'Ontario',
                'country_id' => 1
            ],
            [
                'name' => 'Florence',
                'country_id' => 2 //Italy
            ],
            [
                'name' => 'Palermo',
                'country_id' => 2
            ]
        ];

        foreach ($cities as $city) {
            City::create($city);
        }
    }

Note: Don't forget to import the appropriate model in each seeder.

Finally, in the app/database/seeder/DatabaseSeeder.php add this code.

  public function run()
    {
        $this->call([
            CountrySeeder::class,
            CitySeeder::class
        ]);
    }

Note: To prevent errors put always in first place CountrySeeder::class

The final step in this section is run

php artisan migrate:fresh --seed

Cool!!! Everything is ready to incorporate Laravel Livewire in the next section.

4. Install Laravel Livewire.

Run this command

composer require livewire/livewire

In order to make Livewires works, we need to configure the app/resources/views/welcome.blade.php file like this

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Laravel</title>
    <link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">

    @livewireStyles
</head>

<body>


    @livewireScripts
</body>

</html>

Note: I'm going to use TailwindCSS CDN to keep this tutorial simple. Don't worry if you see a blank page later in this guide will fix that.

5. Create Livewire Component

To create a Livewire component execute this command

php artisan make:livewire CountryDropdown

This generates this output

countrycomponent.png

6. CountryDropdown Component

We need to modify the app/Http/Livewire/CountryDropdown.php file adding this code

<?php

namespace App\Http\Livewire;

use App\Models\City;
use App\Models\Country;
use Livewire\Component;

class CountryDropdown extends Component
{
    public $countries = [], $cities = [];
    public $country, $city;

    public function mount()
    {
        $this->countries = Country::all();
        $this->cities = collect();
    }

    public function updatedCountry($value)
    {
        $this->cities = City::where('country_id', $value)->get();
        $this->city = $this->cities->first()->id ?? null;
    }

    public function render()
    {
        return view('livewire.country-dropdown');
    }
}

I'm going to explain this code.

  • In the mount() method, we load all the countries available to store in our variable $countries also create an empty collection in the variable $cities.

  • The magic comes here in the updatedCountry() function, this runs after $country is updated, or in this case, every time we made a change in the country select, when $country change, we took this value and we can do an Eloquent query selecting only the cities belongs to the Country selected. If you want to learn more about this, you can visit Livewire Lifecycle Hooks

  • $this->city = $this->cities->first()->id ?? null this line means every time the country select change, the cities select will display the first city only when the country select is not null

In this step, we need to search the file app/resources/views/livewire/country-dropdown.blade.php and put this code to generate two selects to display the country and city information

<div>
    <div class="col-span-6 sm:col-span-3">
        <label for="country" class="block text-sm font-medium text-gray-700">Country</label>
        <select id="country" name="country" class="mt-1 block w-full py-2 px-3 border border-gray-300 bg-white rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" wire:model="country">
            <option>--- Select a country ---</option>
            @foreach($countries as $country)
            <option value="{{$country->id}}">{{$country->name}}</option>
            @endforeach
        </select>
    </div>
    <div class="col-span-6 sm:col-span-3 mt-3">
        <label for="city" class="block text-sm font-medium text-gray-700">City</label>
        <select id="city" name="city" class="mt-1 block w-full py-2 px-3 border border-gray-300 bg-white rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" wire:model="city">
            @if($cities->count() == 0)
            <option>You have to select a country before</option>
            @endif
            @foreach($cities as $city)
            <option value="{{$city->id}}">{{$city->name}}</option>
            @endforeach
        </select>
    </div>
</div>

The final step in this tutorial is displaying the component, let's go to the welcome.blade.php in add this code.

<div class="grid place-items-center h-screen">
        <div class="py-4 px-8 bg-white shadow-lg rounded-lg">
            <div class="mb-4 mt-4">
                <h2 class="text-gray-800 text-3xl font-semibold">Laravel Livewire Dependent Dropdown</h2>
            </div>
            <livewire:country-dropdown />
        </div>
</div>

As you can see, we add the component with <livewire:country-dropdown/>.

If everything is correct you should see this. display_component.png

7. Github Repo

Laravel-Livewire-Dependent-Dropdown

Thanks for reading ๐Ÿ™. Happy coding โ˜•.

ย