In this course section, we will build four small demo projects to practice Livewire more. The first project is a dependent dropdown, like a parent and a child.
When we will choose a country, the cities list will be refreshed.
First, let's quickly see what the Migrations and Models look like.
database/migrations/xxx_create_countries_table.php:
Schema::create('countries', function (Blueprint $table) { $table->id(); $table->string('name'); $table->timestamps();});
app/Models/Country.php:
use Illuminate\Database\Eloquent\Relations\HasMany; class Country extends Model{ protected $fillable = [ 'name', ]; public function cities(): HasMany { return $this->hasMany(City::class); }}
database/migrations/xxx_create_cities_table.php:
Schema::create('cities', function (Blueprint $table) { $table->id(); $table->foreignId('country_id'); $table->string('name'); $table->timestamps();});
app/Models/City.php:
class City extends Model{ protected $fillable = [ 'country_id', 'name', ];}
And a simple seeder to have some data in the DB:
$country = Country::create(['name' => 'United Kingdom']);$country->cities()->create(['name' => 'London']);$country->cities()->create(['name' => 'Manchester']);$country->cities()->create(['name' => 'Liverpool']); $country = Country::create(['name' => 'United States']);$country->cities()->create(['name' => 'Washington']);$country->cities()->create(['name' => 'New York City']);$country->cities()->create(['name' => 'Denver']);
For the Livewire component, we will name it just Dropdowns
.
php artisan make:livewire Dropdowns
In the component, we first must get the list of countries in the mount
method and set the cities list to an empty collection.
app/Livewire/Dropdowns.php:
use App\Models\Country;use Illuminate\Support\Collection; class Dropdowns extends Component{ public Collection $countries; public Collection $cities; public function mount(): void { $this->countries = Country::pluck('name', 'id'); $this->cities = collect(); } // ...}
Now let's add inputs in the Blade file.
resources/views/livewire/dropdowns.blade.php:
<form method="POST" wire:submit="save"> <div> <label for="country">Country</label> <select wire:model.live="country" id="country" class="block mt-1 w-full border-gray-300 rounded-md shadow-sm"> <option value="0">-- choose country --</option> @foreach($countries as $id => $country) <option value="{{ $id }}">{{ $country }}</option> @endforeach </select> </div> <div class="mt-4"> <label for="city">City</label> <select wire:model="city" id="city" class="block mt-1 w-full border-gray-300 rounded-md shadow-sm"> @if ($cities->count() == 0) <option value="">-- choose country first --</option> @endif @foreach($cities as $city) <option value="{{ $city->id }}">{{ $city->name }}</option> @endforeach </select> </div> <button class="mt-4 px-4 py-2 bg-gray-800 rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700"> Save </button></form>
The important part here is to use live
for the country input. Otherwise, it won't update the cities list after selecting a country.
Next, we need public properties for country
and city
, which we bind to inputs using wire:model
directive.
app/Livewire/Dropdowns.php:
class Dropdowns extends Component{ public Collection $countries; public Collection $cities; public int $country; public int $city; public function mount(): void { $this->countries = Country::pluck('name', 'id'); $this->cities = collect(); } // ...}
All that is left is to update cities when country
public property is updated. We can use Lifecycle Hook updated
.
app/Livewire/Dropdowns.php:
use App\Models\City; class Dropdowns extends Component{ public Collection $countries; public Collection $cities; public int $country; public int $city; public function mount(): void { $this->countries = Country::pluck('name', 'id'); $this->cities = collect(); } public function updatedCountry($value): void { $this->cities = City::where('country_id', $value)->get(); $this->city = $this->cities->first()->id; } // ..}
When a user selects a country, the lifecycle hook updatedCountry
gets triggered. In this method, we set the cities list and the city
property to the first from the cities
list.