¶Overview
Pada kesempatan kali ini, kita akan belajar membuat sebuah dynamic dependent dropdown atau sebuah dropdown bertingkat menggunakan laravel livewire.
¶Installasi Project
Sebelum memulai pastikan teman-teman sudah menginstall composer
dikarenakan kita akan menggunakan laravel versi terbaru yaitu laravel 11
, maka pastikan teman-teman sudah melakukan installasi php
dengan versi minimal 8.2
, karena kita akan mulai semuanya dari awal, maka kita akan lakukan installasi laravel terlebih dahulu. Untuk installasi laravel, silahkan teman-teman buka terminal dan jalankan perintah berikut ini:
Terminal
composer create-project laravel/laravel livewire-dropdown
Setelah berhasil menjalankan perintah diatas, silahkan tunggu sampai installasi selesai. Setelah itu silahkan jalankan perintah berikut :
terminal
cd livewire-dropdown
Kemudian buka projectnya di text editor teman-teman, dan silahkan buka file .env
untuk mengganti default databasenya, by default Laravel yang di install melalui composer
akan mengarahkan kita ke sqlite
, namun kita akan menggunakan mysql
pada project kali ini. Silahkan teman-teman ganti DB_CONNECTION
menjadi mysql
, dan sesuaikan dengan konfigurasi database teman-teman.
.env
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=livewire_dropdown
DB_USERNAME=root
DB_PASSWORD=
Kemudian tidak lupa kita juga akan mengubah title
dari aplikasi kita dengan cara mengubah APP_NAME
menjadi Livewire Dropdown
.
.env
APP_NAME='Livewire Dropdown'
Setelah itu, Jika teman-teman belum memiliki database dengan nama livewire_dropdown
, maka laravel akan otomatis membuatkan sebuah database baru untuk kita dengan menjalankan perintah di berikut ini :
Terminal
php artisan migrate
Setelah berhasil menjalankan perintah di atas, teman-teman bisa lanjutkan untuk menjalankan projectnya dengan menjalankan perintah berikut :
Terminal
php artisan serve
Jika berhasil, maka project kita akan dijalankan didalam server localhost
dengan port 8000
. Teman-teman bisa membukanya di dalam web browser dengan mengetikan alamat : http://localhost:8000/ , dan akan tampil seperti berikut ini :
Catatan : saat proses development pastikan perintah php artisan serve
selalu dijalankan.
¶Membuat Model & Migration
Setelah berhasil melakukan installasi laravel, disini kita akan lanjutkan untuk pembuatan model, migration, factory dan seeder terlebih dahulu, silahkan teman - teman ikuti beberapa langkah dibawah ini.
¶Model & Migration Category
Silahkan teman - teman buka terminal-nya, kemudian jalankan perintah berikut ini :
Terminal
php artisan make:model Category -m
Jika perintah diatas berhasil dijalankan, maka kita akan dibuatkan sebuah model baru dengan nama Category
. Kemudian, kita tambahkan flag -m
, yang artinya kita juga akan membuat sebuah file baru sesuai dengan nama modelnya yaitu Category
akan tetapi nama migration-nya akan otomatis dibuatkan dalam bentuk plural.
Jika teman - teman perhatikan setelah menjalankan perintah diatas, kita akan mendapatkan 2 buah file baru yang terletak di :
-
app/Models/Category.php
-
database/migration/2024_09_27_085505_create_categories_table.php
Informasi : untuk nama file migration akan digenerate berdasarkan tanggal pembuatannya.
Selanjutnya kita akan menambahkan beberapa attribute baru didalam file migration categories
, silahkan teman - teman buka filenya kemudian ubah kodenya menjadi seperti berikut ini :
2024_09_27_085505_create_categories_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('categories', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('slug');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('categories');
}
};
Dari perubahan kode diatas, kita menambahan beberapa attribute baru didalam function up, kurang lebih penjelasannya seperti berikut ini :
ATTRIBUTE |
TYPE DATA |
name |
string |
slug |
string |
Setelah berhasil menambahkan beberapa attribute di dalam file migration, maka sekarang kita lanjutkan untuk menambahkan mass assigment di dalam file model, tujuannya agar attribute yang sudah kita tambahkan diatas dapat melakukan manipulasi data, seperti proses insert, update dan delete.
Silahkan teman - teman buka file app/Models/Category.php
, kemudian masukan kode berikut ini :
Category.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
use HasFactory;
protected $fillable = ['name', 'slug'];
}
Dari perubahan kode di atas, kita menambahkan properti baru dengan nama $fillable
, dimana berisi attribute yang sudah kita buat sebelumnya di dalam migration categories
.
¶Model & Migration Subcategory
Silahkan teman - teman buka terminal-nya, kemudian jalankan perintah berikut ini :
Terminal
php artisan make:model Subategory -m
Jika perintah diatas berhasil dijalankan, maka kita akan dibuatkan sebuah model baru dengan nama SubCategory
. Kemudian, kita tambahkan flag -m
, yang artinya kita juga akan membuat sebuah file baru sesuai dengan nama modelnya yaitu SubCategory
akan tetapi nama migration-nya akan otomatis dibuatkan dalam bentuk plural.
Jika teman - teman perhatikan setelah menjalankan perintah diatas, kita akan mendapatkan 2 buah file baru yang terletak di :
-
app/Models/SubCategory.php
-
database/migration/2024_09_27_085511_create_sub_categories_table.php
Informasi : untuk nama file migration akan digenerate berdasarkan tanggal pembuatannya.
Selanjutnya kita akan menambahkan beberapa attribute baru didalam file migration sub_categories
, silahkan teman - teman buka filenya kemudian ubah kodenya menjadi seperti berikut ini :
2024_09_27_085511_create_sub_categories_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('sub_categories', function (Blueprint $table) {
$table->id();
$table->foreignId('category_id')->constrained('categories');
$table->string('name');
$table->string('slug');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('sub_categories');
}
};
Dari perubahan kode diatas, kita menambahan beberapa attribute baru didalam function up, kurang lebih penjelasannya seperti berikut ini :
ATTRIBUTE |
TYPE DATA |
category_id |
foreignId |
name |
string |
slug |
string |
Pada kode diatas, kita juga menambahkan sebuah kolom relasi dari tabel products ke tabel categories.
2024_09_27_085511_create_sub_categories_table.php
$table->foreignId('category_id')->constrained('categories');
Kode diatas artinya attribute category_id
merupakan foreign key
dari table categories attribute id
.
Setelah berhasil menambahkan beberapa attribute di dalam file migration, maka sekarang kita lanjutkan untuk menambahkan mass assigment di dalam file model, tujuannya agar attribute yang sudah kita tambahkan diatas dapat melakukan manipulasi data, seperti proses insert, update dan delete.
Silahkan teman - teman buka file app/Models/SubCategory.php
, kemudian masukan kode berikut ini :
SubCategory.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class SubCategory extends Model
{
use HasFactory;
protected $fillable = ['name', 'category_id', 'slug'];
public function category()
{
return $this->belongsTo(Category::class);
}
}
Dari perubahan kode di atas, kita menambahkan properti baru dengan nama $fillable
, dimana berisi attribute yang sudah kita buat sebelumnya di dalam migration categories
.
selain itu kita juga menambahkan sebuah relasi dari tabel products ke tabel categories yang kita beri nama dengan category
, disini jenis relasi yang kita gunakan adalah belongsTo
yang artinya 1 category bisa memiliki berbagai macam subcategory.
Setelah berhasil membuat model dan migration diatas, silahkan teman - teman buka terminal-nya kemudian jalankan perintah berikut ini :
Terminal
php artisan migrate
¶Membuat Factory
Setelah berhasil membuat model yang kita perlukan, disini kita akan lanjutkan untuk membuat sebuah factory, gunanya untuk melakukan insert data baru kedalam database secara random sesuai jumlah yang kita tentukan.
¶Factory Category
Silahkan teman - teman buka terminal-nya kemudian jalankan perintah berikut ini.
Terminal
php artisan make:factory CategoryFactory
Selanjutnya silahkan buka file tersebut yang terletak di database/factories
, kemudian masukan kode berikut ini.
CategoryFactory.php
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Category>
*/
class CategoryFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
$name = $this->faker->sentence();
return [
'name' => $name,
'slug' => str()->slug($name),
];
}
}
Pada kode daitas, pertama - tama kita membuat sebuah variabel baru dengan nama $name
yang kita assign value-nya dengan faker sentence
.
$name = $this->faker->sentence();
Selanjutnya pada method definition
, kita menambahkan beberapa key diantaranya name
dan slug
.
CategoryFactory.php
public function definition(): array
{
$name = $this->faker->sentence();
return [
'name' => $name,
'slug' => str()->slug($name),
];
}
Pada key name
kita menggambil sebuah variabel $name
yang telah kita definisikan sebelumnya, dan untuk key slug
kita memanggil sebuah helper str()->slug
untuk mengubah name
menjadi slug
.
¶Factory Subcategory
Silahkan teman - teman buka terminal-nya kemudian jalankan perintah berikut ini.
Terminal
php artisan make:factory SubcategoryFactory
Selanjutnya silahkan buka file tersebut yang terletak di database/factories
, kemudian masukan kode berikut ini.
SubcategoryFactory.php
<?php
namespace Database\Factories;
use App\Models\Category;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Subcategory>
*/
class SubcategoryFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
$name = $this->faker->sentence();
return [
'category_id' => Category::inRandomOrder()->first()->id,
'name' => $name,
'slug' => str()->slug($name),
];
}
}
Pada kode daitas, pertama - tama kita import model Category
terlebih dahulu.
SubcategoryFactory.php
use App\Models\Category;
Kemudian kita membuat sebuah variabel baru dengan nama $name
yang kita assign value-nya dengan faker sentence
.
$name = $this->faker->sentence();
Selanjutnya pada method definition
, kita menambahkan beberapa key diantaranya category_id
, name
dan slug
.
CategoryFactory.php
public function definition(): array
{
$name = $this->faker->sentence();
return [
'category_id' => Category::inRandomOrder()->first()->id,
'name' => $name,
'slug' => str()->slug($name),
];
}
Pada key category_id
kita memanggil sebuah id
data category
secara acak menggunakan method inRandomOrder
dan method first
kita gunakan untuk menangkap data pertama yang tampil. Selanjutnya pada key name
kita menggambil sebuah variabel $name
yang telah kita definisikan sebelumnya, dan untuk key slug
kita memanggil sebuah helper str()->slug
untuk mengubah name
menjadi slug
.
¶Menjalankan Factory
Setelah berhasil membuat beberapa factory diatas, kita akan lanjutkan untuk melakukan pemanggilan data factory tersebut. Silahkan teman - teman buka file DatabaseSeeder.php
yang terletak di database/seeders
, kemudian ubah kodenya menjadi berikut ini.
DatabaseSeeder.php
<?php
namespace Database\Seeders;
use App\Models\User;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use App\Models\Category;
use App\Models\SubCategory;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*/
public function run(): void
{
Category::Factory(12)->create();
SubCategory::Factory(40)->create();
}
}
Pada kode diatas, pertama - tama kita import terlebih dahulu model Category
dan SubCategory
.
DatabaseSeeder.php
use App\Models\Category;
use App\Models\SubCategory;
Selanjutnya pada method run
, kita memanggil beberapa seeder dan factory yang telah kita buat sebelumnya.
DatabaseSeeder.php
Category::Factory(12)->create();
SubCategory::Factory(40)->create();
Terakhir, silahkan teman - teman buka terminalnya kemudian jalankan perintah berikut ini.
¶Installasi Laravel Livewire
Silahkan teman - teman buka terminalnya kemudian jalankan perintah berikut ini.
Terminal
composer require livewire/livewire
Setelah proses installasi selesai, silahkan teman - teman jalankan perintah berikut ini.
Terminal
php artisan livewire:publish --config
Jika perintah diatas berhasil dijalankan, maka kita akan mendapatkan file baru dengan nama Livewire.php
didalam folder config
.
¶Membuat Layout Aplikasi
Silahkan teman - teman buka terminal-nya kemudian jalankan perintah berikut ini.
Terminal
php artisan livewire:layout
Jika perintah diatas berhasil dijalankan, maka kita akan mendapatkan file baru dengan nama app.blade.php
yang terletak didalam folder resources/views/components/layouts
.
Silahkan buka file tersebut kemudian ubah kodenya menjadi seperti berikut ini.
app.blade.php
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ $title }} - {{ config('app.name', 'Laravel') }}</title>
@livewireStyles
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500&family=Quicksand:wght@300;400;500;600&display=swap" rel="stylesheet">
</head>
<body style="background-color: #f5f5f5; font-family: 'Quicksand', sans-serif">
<div class="container mt-5 mb-5">
{{ $slot }}
</div>
@livewireScripts
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
Pada kode diatas, pertama - tama kita memanggil sebuah blade directive @livewireStyles
dan @ @livewireScripts
didalam layout kita.
Kemudian kita juga menambahkan CSS dan Js dari Bootstrap , karena disini kita akan memanfaatkan-nya sebagai tools kita dalam membuat user interface-nya.
Selanjutnya kita juga mendefinisikan sebuah variabel $slot
yang berfungsi untuk meletakan kontent secara dinamis kedalam layout kita.
¶Membuat Component Home
Silahkan teman-teman buka terminal-nya, kemudian jalankan perintah berikut ini :
Terminal
Terminal
php artisan make:livewire Home
Setelah berhasil menjalankan perintah diatas, kita akan mendapatkan 2 buah file baru yang terletak di :
-
app/Livewire/Home.php
-
resources/views/livewire/home.blade.php
Silahkan teman-teman buka file App/Livewire/Home.php
, kemudian tambahkan kode berikut ini :
Home.php
<?php
namespace App\Livewire;
use Livewire\Component;
use App\Models\Category;
use App\Models\SubCategory;
use Livewire\Attributes\Title;
class Home extends Component
{
public $category = 'choose';
public function getSubcategories()
{
return SubCategory::whereCategoryId($this->category)->orderBy('name')->get();
}
public function categories()
{
return Category::orderBy('name')->get();
}
#[Title('Home')]
public function render()
{
return view('livewire.home', [
'categories' => $this->categories(),
'subcategories' => $this->getSubcategories(),
]);
}
}
Pada kode diatas, pertama - tama kita mendefiniskan sebuah property category
dengan value choose
.
Home.php
public $category = 'choose';
Selanjutnya kita membuat sebuah method dengan nama getSubCategories
.
Home.php
public function getSubcategories()
{
return SubCategory::whereCategoryId($this->category)->orderBy('name')->get();
}
Method tersebut akan mengembalikan sebuah data collection SubCategory
yang telah di filter menggunakan method whereCategoryId
, sesuai dengan value dari property category
.
Kemudian kita juga membuat sebuah method baru lagi dengan nama categories
.
Home.php
public function categories()
{
return Category::orderBy('name')->get();
}
Method ini kita gunakan untuk menampilkan semua data Category
yang kita miliki dan disini kita urutkan datanya berdasarkan nama category-nya menggunakan method orderBy
.
Selanjutnya kita mendefiniskan sebuah attribute title
.
Home.php
#[Title('Home')]
Terakhir, pada method render
kita hanya mengembalikan sebuah view dan tidak lupa kita kirimkan data yang telah kita definisikan sebelumnya.
Home.php
return view('livewire.home', [
'categories' => $this->categories(),
'subcategories' => $this->getSubcategories(),
]);
¶Route Component Home
Setelah berhasil membuat component home, sekarang kita akan lanjutkan untuk membuat route-nya, Silahkan teman - teman buka file routes/web.php
, kemudian tambahkan kode berikut ini :
web.php
<?php
use App\Livewire\Home;
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return view('welcome');
});
Route::get('/home', Home::class);
Dari perubahan kode diatas, kita menambahkan sebuah route baru dengan nama home
,
¶View Component Home
Silahkan teman - teman buka file yang bernama home.blade.php
yang terletak di dalam folder resources/views/livewire
, kemudian tambahkan kode berikut ini :
home.blade.php
<div class="row d-flex justify-content-center">
<div class="col-10">
<div class="card">
<div class="card-header fw-bold">
Livewire Dynamic Dependent Dropdown
</div>
<div class="card-body">
<div class="form-group mb-4">
<label class="form-label">Kategori</label>
<select class="form-control" wire:model="category" wire:change="getSubcategories()">
<option selected disabled value="choose">Silahkan pilih kategori</option>
@foreach ($categories as $category)
<option value="{{ $category->id }}">{{ $category->name }}</option>
@endforeach
</select>
</div>
<div class="form-group">
<label class="form-label">Subkategori</label>
<button class="btn btn-dark btn-sm" style="width: 100%" type="button"
disabled
wire:loading
wire:target="getSubcategories">
<span class="spinner-grow spinner-grow-sm" role="status" aria-hidden="true"></span>
Loading...
</button>
<select
class="form-control"
wire:loading.class="d-none"
wire:target="getSubcategories"
>
<option selected disabled>Silahkan pilih subkategori</option>
@foreach ($subcategories as $subcategory)
<option value="{{ $subcategory->id }}">{{ $subcategory->name }}</option>
@endforeach
</select>
</div>
</div>
</div>
</div>
</div>
Pada kode diatas, kita membuat sebuah element select yang telah kita definiskan sebuah wire:model
dan wire:change
.
home.blade.php
<select class="form-control" wire:model="category" wire:change="getSubcategories()">
<option selected disabled value="choose">Silahkan pilih kategori</option>
@foreach ($categories as $category)
<option value="{{ $category->id }}">{{ $category->name }}</option>
@endforeach
</select>
Untuk wire:model
kita arahkan ke property category
yang telah kita buat sebelumnya pada component home, dan wire:change
kita arahkan ke sebuah method getSubcategories
. Kemudian tiap kali user melakukan pemilihan sebuah category
baru, maka method getSubcategories
akan dipanggil.
Selanjutnya kita memanfaatkan sebuah html directive livewre yaitu wire:loading
dan wire:target
untuk menampilkan sebuah loading button, loading button hanya akan ditampilkan jika method getSubcategories
dipanggil.
home.blade.php
<button class="btn btn-dark btn-sm" style="width: 100%" type="button"
disabled
wire:loading
wire:target="getSubcategories">
<span class="spinner-grow spinner-grow-sm" role="status" aria-hidden="true"></span>
Loading...
</button>
Pada saat method getSubcategories
sedang dipanggil kita memanfaatkan html directive livewire wire:loading.class
untuk menambahkan class d-none
yang artinya element select akan disembunyikan saat proses sedang berjalan dan ketika proses pemanggilan method getSubcategories
telah selsai kita akan tampilkan element select yang memiliki data subcategories
sesuai dengan category
yang telah kita pilih.
home.blade.php
<select
class="form-control"
wire:loading.class="d-none"
wire:target="getSubcategories"
>
<option selected disabled>Silahkan pilih subkategori</option>
@foreach ($subcategories as $subcategory)
<option value="{{ $subcategory->id }}">{{ $subcategory->name }}</option>
@endforeach
</select>
¶Screenshoot Hasil
¶Penutup
Pada artikel ini kita telah berhasil membuat dropdown dinamis menggunakan laravel livewire, jika teman - teman ada pertanyaan atau kendala bisa langsung ke telegram saya Rafi Taufiqurrahman. Semoga bermanfaat terimakasih : )