¶Pendahuluan
Pada artikel kali ini, kita akan sama - sama membuat sebuah module category yang kita bagi menjadi beberapa langkah diatanya sebagai berikut :
- Membuat Component Index
- Membuat Component Create
- Membuat Component Edit
setiap langkah diatas, nanti-nya akan kita buat menggunakan component laravel livewire.
¶Component Category Index
Silahkan teman-teman buka terminal-nya, kemudian jalankan perintah berikut ini :
Terminal
php artisan make:livewire pages.categories.index
Setelah berhasil menjalankan perintah diatas, kita akan mendapatkan 2 buah file baru yang terletak di :
-
app/Livewire/Pages/Categories/Index.php
-
resources/views/livewire/pages/categories/index.blade.php
Silahkan teman-teman buka file App/Livewire/Pages/Categories/Index.php
, kemudian tambahkan kode berikut ini :
Categories/Index.php
<?php
namespace App\Livewire\Pages\Categories;
use Livewire\Component;
use App\Models\Category;
use Livewire\Attributes\Url;
use Livewire\WithPagination;
use Livewire\Attributes\Title;
use Livewire\Attributes\Layout;
use Illuminate\Support\Facades\Storage;
class Index extends Component
{
use WithPagination;
// define layout
#[Layout('layouts.app')]
// define title
#[Title('Categories')]
// define proprty
#[Url]
public $search;
public $path = 'public/categories/';
// define function delete
public function delete($id)
{
// get category data by id
$category = Category::findOrFail($id);
// delete category image
Storage::disk('local')->delete($this->path.basename($category->image));
// delete category data
$category->delete();
}
public function render()
{
// table heads
$table_heads = ['No', 'Name', 'Image', 'Action'];
// list categories data
$categories = Category::query()
->when($this->search, fn($query) => $query->where('name', 'like', '%' .$this->search. '%'))
->latest()
->paginate(7);
// render view
return view('livewire.pages.categories.index', compact('categories', 'table_heads'));
}
}
Pada kode diatas pertama - tama, kita menggunakan sebuah trait
yang telah disedikan oleh livewire.
Categories/Index.php
use WithPagination;
Selanjutnya kita mendefinisikan sebuah attribute title
dan layout
.
Categories/Index.php
// define layout
#[Layout('layouts.app')]
// define title
#[Title('Categories')]
Kemudian kita juga mendefinisikan beberapa property diantaranya search
dan path
.
Categories/Index.php
#[Url]
public $search;
public $path = 'public/categories/';
Method Delete
Method ini kita gunakan untuk menghapus data category
sesuai dengan parameter id
yang kita kirimkan.
Categories/Index.php
// define function delete
public function delete($id)
{
// get category data by id
$category = Category::findOrFail($id);
// delete category image
Storage::disk('local')->delete($this->path.basename($category->image));
// delete category data
$category->delete();
}
Didalam method tersebut, pertama -tama kita mencari data category
yang sesuai berdasarkan paramater id
yang dikirimkan.
Categories/Index.php
// get category data by id
$category = Category::findOrFail($id);
Setelah data berhasil ditemukan, maka kita lanjutkan untuk menghapus gambar category
.
Categories/Index.php
// delete category image
Storage::disk('local')->delete($this->path.basename($category->image));
Kemudian, kita juga menghapus seluruh data category
yang ada sesuai dengan paramater id
yang dikirimkan.
Categories/Index.php
// delete category data
$category->delete();
Method Render
Method ini kita gunakan untuk menampilkan data category
yang kita miliki didalam database.
Categories/Index.php
public function render()
{
// table heads
$table_heads = ['No', 'Name', 'Image', 'Action'];
// list categories data
$categories = Category::query()
->when($this->search, fn($query) => $query->where('name', 'like', '%' .$this->search. '%'))
->latest()
->paginate(7);
// render view
return view('livewire.pages.categories.index', compact('categories', 'table_heads'));
}
Pada kode diatas, pertama - tama kita mendefinisikan sebuah variabel baru dengan nama table_heads
.
Categories/Index.php
// table heads
$table_heads = ['No', 'Name', 'Image', 'Action'];
Selanjutnya kita membuat sebuah variabel baru dengan nama categories
yang dimana, variabel tersebut menampung seluruh data category
yang kita miliki, disini kita juga melakukan filtering data sesuai dengan value dari property search
, method latest
kita gunakan untuk menampilkan urutan data paling baru dan kita buat pembatasan data yang ditampilkan hanya sebanyak 7 data menggunakan method paginate
.
Categories/Index.php
// list categories data
$categories = Category::query()
->when($this->search, fn($query) => $query->where('name', 'like', '%' .$this->search. '%'))
->latest()
->paginate(7);
Kemudian, data category
tersebut kita lempar kedalam view dengan cara menggunakan sebuah method compact
, agar data tersebut bisa kita gunakan didalam view.
Categories/Index.php
// render view
return view('livewire.pages.categories.index', compact('categories', 'table_heads'));
¶Route Component Category Index
Setelah berhasil membuat component category index, 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 Illuminate\Support\Facades\Route;
use App\Livewire\Pages\Categories\Index as CategoryIndex;
Route::view('/', 'welcome');
Route::group(['middleware' => ['auth']], function(){
// categories route
Route::group(['prefix' => 'categories', 'as' => 'categories.'], function(){
Route::get('/', CategoryIndex::class)->name('index');
});
});
Route::view('dashboard', 'dashboard')
->middleware(['auth', 'verified'])
->name('dashboard');
Route::view('profile', 'profile')
->middleware(['auth'])
->name('profile');
require __DIR__.'/auth.php';
Dari perubahan kode diatas, kita menambahkan sebuah route baru dengan nama categories
, untuk memastikan route yang kita buat berfungsi, teman - teman bisa jalankan perintah berikut ini dalam terminal.
Terminal
php artisan r:l --name=categories
Setelah perintah artisan diatas berhasil dijalankan maka kita akan mendapatkan output, kurang lebih seperti berikut ini.
Terminal
GET|HEAD categories .......................................... categories.index › App\Livewire\Pages\Categories\Index
¶Navigasi Category Index
Sebelum membuat navigasi category index, kita akan memodifikasi sedikit layout dari aplikasi kita, agar attribute title
yang telah kita definisikan didalam component category index dapat dijalankan, silahkan teman - teman buka file yang bernama app.blade.php
yang terletak didalam folder resources/views/layouts
, kemudian tambahkan kode 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">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>{{ $title }} - {{ config('app.name', 'Laravel') }}</title>
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet" />
<!-- Scripts -->
@vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body class="font-sans antialiased">
<div class="min-h-screen bg-gray-100">
<livewire:layout.navigation />
<!-- Page Heading -->
@if (isset($header))
<header class="bg-white shadow">
<div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
{{ $header }}
</div>
</header>
@endif
<!-- Page Content -->
<main>
{{ $slot }}
</main>
</div>
</body>
</html
Pada kode diatas, pada bagian element title
kita menambahkan sebuah variabel baru dengan nama title
, title tersebut akan berisi data dinamis sesuai attribute #title
yang telah kita definisikan didalam component livewire. Selanjutnya kita akan membuat navigasi untuk route category index kita, silahkan teman - teman buka file yang bernama navigation.blade.php
yang terletak di folder resources/views/livewire/layout
, kemudian ubah kodenya menjadi berikut ini :
navigation.blade.php
<?php
use App\Livewire\Actions\Logout;
use Livewire\Volt\Component;
new class extends Component
{
/**
* Log the current user out of the application.
*/
public function logout(Logout $logout): void
{
$logout();
$this->redirect('/', navigate: true);
}
}; ?>
<nav x-data="{ open: false }" class="bg-white border-b border-gray-100">
<!-- Primary Navigation Menu -->
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between h-16">
<div class="flex">
<!-- Logo -->
<div class="shrink-0 flex items-center">
<a href="{{ route('dashboard') }}" wire:navigate>
<x-application-logo class="block h-9 w-auto fill-current text-gray-800" />
</a>
</div>
<!-- Navigation Links -->
<div class="hidden space-x-8 sm:-my-px sm:ms-10 sm:flex">
<x-nav-link :href="route('dashboard')" :active="request()->routeIs('dashboard')" wire:navigate>
{{ __('Dashboard') }}
</x-nav-link>
<x-nav-link :href="route('categories.index')" :active="request()->routeIs('categories*')" wire:navigate>
{{ __('Categories') }}
</x-nav-link>
</div>
</div>
<!-- Settings Dropdown -->
<div class="hidden sm:flex sm:items-center sm:ms-6">
<x-dropdown align="right" width="48">
<x-slot name="trigger">
<button class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-500 bg-white hover:text-gray-700 focus:outline-none transition ease-in-out duration-150">
<div x-data="{{ json_encode(['name' => auth()->user()->name]) }}" x-text="name" x-on:profile-updated.window="name = $event.detail.name"></div>
<div class="ms-1">
<svg class="fill-current h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
</svg>
</div>
</button>
</x-slot>
<x-slot name="content">
<x-dropdown-link :href="route('categories.index')" wire:navigate>
{{ __('Categories') }}
</x-dropdown-link>
<x-dropdown-link :href="route('profile')" wire:navigate>
{{ __('Profile') }}
</x-dropdown-link>
<!-- Authentication -->
<button wire:click="logout" class="w-full text-start">
<x-dropdown-link>
{{ __('Log Out') }}
</x-dropdown-link>
</button>
</x-slot>
</x-dropdown>
</div>
<!-- Hamburger -->
<div class="-me-2 flex items-center sm:hidden">
<button @click="open = ! open" class="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 focus:text-gray-500 transition duration-150 ease-in-out">
<svg class="h-6 w-6" stroke="currentColor" fill="none" viewBox="0 0 24 24">
<path :class="{'hidden': open, 'inline-flex': ! open }" class="inline-flex" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
<path :class="{'hidden': ! open, 'inline-flex': open }" class="hidden" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</div>
</div>
<!-- Responsive Navigation Menu -->
<div :class="{'block': open, 'hidden': ! open}" class="hidden sm:hidden">
<div class="pt-2 pb-3 space-y-1">
<x-responsive-nav-link :href="route('dashboard')" :active="request()->routeIs('dashboard')" wire:navigate>
{{ __('Dashboard') }}
</x-responsive-nav-link>
<x-responsive-nav-link :href="route('categories.index')" :active="request()->routeIs('categories*')" wire:navigate>
{{ __('Categories') }}
</x-responsive-nav-link>
</div>
<!-- Responsive Settings Options -->
<div class="pt-4 pb-1 border-t border-gray-200">
<div class="px-4">
<div class="font-medium text-base text-gray-800" x-data="{{ json_encode(['name' => auth()->user()->name]) }}" x-text="name" x-on:profile-updated.window="name = $event.detail.name"></div>
<div class="font-medium text-sm text-gray-500">{{ auth()->user()->email }}</div>
</div>
<x-responsive-nav-link :href="route('categories.index')" wire:navigate>
{{ __('Categories') }}
</x-responsive-nav-link>
<div class="mt-3 space-y-1">
<x-responsive-nav-link :href="route('profile')" wire:navigate>
{{ __('Profile') }}
</x-responsive-nav-link>
<!-- Authentication -->
<button wire:click="logout" class="w-full text-start">
<x-responsive-nav-link>
{{ __('Log Out') }}
</x-responsive-nav-link>
</button>
</div>
</div>
</div>
</nav>
Pada kode diatas, kita menambahkan beberapa navigasi yang mengarah ke route categories.index
, dengan menggunakan, beberapa component yang telah disediakan oleh laravel yaitu :
-
<x-nav-link/>
.
-
<x-dropdown-link/>
.
-
<x-responsive-nav-link/>
¶View Component Category Index
Silahkan teman - teman buka file yang bernama index.blade.php
yang terletak di dalam folder resources/views/livewire/pages/categories
, kemudian tambahkan kode berikut ini :
index.blade.php
<div>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Categories') }}
</h2>
</x-slot>
<div class="py-12 px-4">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="mb-4 flex items-center justify-between gap-4">
<x-button type="create" href="#">
<x-slot name="title">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"
stroke-linejoin="round"
class="icon icon-tabler icons-tabler-outline icon-tabler-circle-plus">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0" />
<path d="M9 12h6" />
<path d="M12 9v6" />
</svg>
<span class="hidden md:block">Create New Category</span>
</x-slot>
</x-button>
<div class="w-full md:w-1/2">
<x-search placeholder="Search categories by name.."/>
</div>
</div>
<x-table :heads="$table_heads" title="List Data Categories">
@forelse ($categories as $key => $category)
<tr>
<td class="whitespace-nowrap px-6 py-2 text-gray-700 rounded-b-lg text-sm">
{{ $key + $categories->firstItem() }}</td>
<td class="whitespace-nowrap px-6 py-2 text-gray-700 rounded-b-lg text-sm">{{ $category->name }}
</td>
<td class="whitespace-nowrap px-6 py-2 text-gray-700 rounded-b-lg text-sm">
<img src="{{ $category->image }}" alt="{{ $category->name }}"
class="object-cover w-10 h-10 rounded-lg" />
</td>
<td class="whitespace-nowrap px-6 py-2 text-gray-700 rounded-b-lg text-sm">
<div class="flex items-center gap-2">
<x-button type="edit" title="Edit" href="#"/>
<x-button type="delete" title="Delete" id="delete({{ $category->id }})"/>
</div>
</td>
</tr>
@empty
<tr>
<td colspan="4"
class="whitespace-nowrap px-6 py-2 text-rose-700 rounded-b-lg text-sm text-center">
Sorry, we couldn't find anything...
</td>
</tr>
@endforelse
</x-table>
<div class="mt-4">
{{ $categories->links() }}
</div>
</div>
</div>
</div>
Pada kode diatas, kita melakukan pemanggilan beberapa components yang telah kita buat sebelumnya diantaranya :
-
<x-button/>
- props yang digunakan type
, href
dan title
.
-
<x-search/>
- props yang digunakan placeholder
.
-
<x-table/>
- props yang digunakan heads
dan title
.
Untuk pencarian data, kita menggunakan component search yang kita buat sebelumnya, dengan kode kurang lebih seperti berikut ini :
search.blade.php
@props(['placeholder' => ''])
<div class="relative flex w-full flex-col gap-1 text-gray-400">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" aria-hidden="true" class="absolute left-2.5 top-1/2 size-5 -translate-y-1/2 text-gray-700/50">
<path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z" />
</svg>
<input
type="test"
class="w-full rounded-lg border border-gray-200 text-gray-700 py-2 px-4 pl-10 pr-2 text-sm focus:outline-none disabled:cursor-not-allowed disabled:opacity-750"
wire:model.live="search"
placeholder="{{ $placeholder }}"
aria-label="search"
/>
</div>
Pada kode daitas, kita membuat sebuah element input dengan attribute bawaan livewire wire:model.live
dengan value search
. Disini sehingga jika element input kita masukan kata kunci, dia akan langsung mencari data sesuai dengan property search yang telah kita definisikan di component category index.
Untuk paginate halaman, kita buat kurang lebih seperti berikut ini :
index.blade.php
<div class="mt-4">
{{ $categories->links() }}
</div>
Dan untuk menampilkan perulangan data kita menggunakan kode, kurang lebih seperti berikut ini :
index.blade.php
@forelse ($categories as $key => $category)
// ....
@empty
// ....
@endforelse
Pada kode diatas, variabel categories
kita dapatkan dari passing data yang ada di component category index didalam method render()
.
¶Component Category Create
Setelah berhasil menampilkan data category
, disini kita akan lanjutkan untuk membuat sebuah component untuk menghandle pembuatan data category baru. Silahkan teman-teman buka terminal-nya, kemudian jalankan perintah berikut ini :
Terminal
php artisan make:livewire pages.categories.create
Setelah berhasil menjalankan perintah diatas, kita akan mendapatkan 2 buah file baru yang terletak di :
-
app/Livewire/Pages/Categories/Create.php
-
resources/views/pages/categories/create.blade.php
Silahkan teman-teman buka file App/Livewire/Pages/Categories/Create.php
, kemudian tambahkan kode berikut ini :
Categories/Create.php
<?php
namespace App\Livewire\Pages\Categories;
use Livewire\Component;
use App\Models\Category;
use Livewire\WithFileUploads;
use Livewire\Attributes\Title;
use Livewire\Attributes\Layout;
class Create extends Component
{
use WithFileUploads;
// define layout
#[Layout('layouts.app')]
// define title
#[Title('Create Category')]
// define property
public $path = 'public/categories/';
public $name;
public $image;
// define validation
public function rules()
{
return [
'name' => 'required|string|min:3|max:255|unique:categories',
'image' => 'required|image|max:2048',
];
}
// define function save
public function save()
{
// call validation
$this->validate();
// store image category
$this->image->storeAs(path: $this->path, name: $this->image->hashName());
// create new category data
Category::create([
'name' => $this->name,
'slug' => str()->slug($this->name),
'image' => $this->image->hashName(),
]);
// render view
return $this->redirect('/categories', navigate:true);
}
public function render()
{
return view('livewire.pages.categories.create');
}
}
Pada kode diatas pertama - tama, kita menggunakan sebuah trait
yang telah disedikan oleh livewire, trait ini berfungsi sebagai upload file di livewire.
Categories/Create.php
use WithFileUploads;
Selanjutnya kita mendefinisikan sebuah attribute title
dan layout
.
Categories/Create.php
// define layout
#[Layout('layouts.app')]
// define title
#[Title('Create Category')]
Kemudian kita juga mendefinisikan beberapa property diantaranya path
, name
dan image
.
Categories/Create.php
// define property
public $path = 'public/categories/';
public $name;
public $image;
Berikutnya kita juga mendefinisikan sebuah validasi, menggunakan method rules
.
Categories/Create.php
// define validation
public function rules()
{
return [
'name' => 'required|string|min:3|max:255|unique:categories',
'image' => 'required|image|max:2048',
];
}
Method Save
Method ini kita gunakan untuk melakukan proses penambahan data kedalam tabel categories
kita.
Categories/Create.php
// define function save
public function save()
{
// call validation
$this->validate();
// store image category
$this->image->storeAs(path: $this->path, name: $this->image->hashName());
// create new category data
Category::create([
'name' => $this->name,
'slug' => str()->slug($this->name),
'image' => $this->image->hashName(),
]);
// render view
return $this->redirect('/categories', navigate:true);
}
Didalam method tersebut, pertama - tama kita memangil validasi yang telah kita buat sebelumnya
Categories/Create.php
// call validation
$this->validate();
Selanjutnya kita memanfaatkan method storeAs
untuk menghandle proses penyimpanan data gambar kita.
Categories/Create.php
// store image category
$this->image->storeAs(path: $this->path, name: $this->image->hashName());
Kemudian jika request yang kita kirimkan sudah sesuai dengan kriteria validasi yang kita definisikan, maka kita lakukan insert data baru kedalam tabel categories
menggunakan method create
.
Categories/Create.php
// create new category data
Category::create([
'name' => $this->name,
'slug' => str()->slug($this->name),
'image' => $this->image->hashName(),
]);
Terakhir kita akan diarahkan ke sebuah route yang bernama categories.index
, disini kita memanfaat redirect dari livewire navigate true
yang artinya kita akan berpindah halaman tanpa melakukan reload page.
Categories/Create.php
// render view
return $this->redirect('/categories', navigate:true);
Method Render
Method ini kita gunakan untuk menampilkan sebuah halaman create data category.
Categories/Create.php
public function render()
{
// render view
return view('livewire.pages.categories.create');
}
Pada kode diatas kita hanya mengembalikan sebuah view dengan nama livewire.pages.categories.create
.
Categories/Create.php
// render view
return view('livewire.pages.categories.create');
¶Route Component Category Create
Setelah berhasil membuat component category create, 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 Illuminate\Support\Facades\Route;
use App\Livewire\Pages\Categories\Index as CategoryIndex;
use App\Livewire\Pages\Categories\Create as CategoryCreate;
Route::view('/', 'welcome');
Route::group(['middleware' => ['auth']], function(){
// categories route
Route::group(['prefix' => 'categories', 'as' => 'categories.'], function(){
Route::get('/', CategoryIndex::class)->name('index');
Route::get('/create', CategoryCreate::class)->name('create');
});
});
Route::view('dashboard', 'dashboard')
->middleware(['auth', 'verified'])
->name('dashboard');
Route::view('profile', 'profile')
->middleware(['auth'])
->name('profile');
require __DIR__.'/auth.php';
Dari perubahan kode diatas, kita menambahkan sebuah route baru dengan nama categories
, untuk memastikan route yang kita buat berfungsi, teman - teman bisa jalankan perintah berikut ini dalam terminal.
Terminal
php artisan r:l --name=categories
Setelah perintah artisan diatas berhasil dijalankan maka kita akan mendapatkan output, kurang lebih seperti berikut ini.
Terminal
GET|HEAD categories .......................................... categories.index › App\Livewire\Pages\Categories\Index
GET|HEAD categories/create ................................. categories.create › App\Livewire\Pages\Categories\Create
¶View Component Category Create
Setelah berhasil membuat route untuk penambahan data category, disini akan kita lanjutkan untuk pembuatan view tambah data category. silahkan teman - teman buka file yang bernama create.blade.php
yang terletak di resources/views/livewire/pages/categories
, kemudian tambahkan kode berikut ini :
create.blade.php
<div>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Create New Category') }}
</h2>
</x-slot>
<div class="py-12 px-4">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<x-card title="Create New Category">
<form wire:submit.prevent="save">
<div class="mb-4">
<x-input type="text" label="Category Name" name="name" :value="old('name')" placeholder="Enter a category name..."/>
</div>
<div class="mb-4">
<x-input label="Category Image" type="file" name="image"/>
</div>
<div class="flex items-center gap-2">
<x-button type="submit" title="Create Category"/>
<x-button type="cancel" title="Go Back" :href="route('categories.index')"/>
</div>
</form>
</x-card>
</div>
</div>
</div>
Pada kode diatas, kita melakukan pemanggilan beberapa components yang telah kita buat sebelumnya diantaranya :
-
<x-card/>
- props yang digunakan title
-
<x-button/>
- props yang digunakan type
, href
dan title
.
-
<x-input/>
- props yang digunakan type
, label
, name
, value
dan placeholder
.
Pada bagian form action
kita menggunakan attribute yang disediakan oleh livewire yaitu wire:submit.prevent
kemudian kita set valuenya dengan method save
yang telah kita buat sebelumnya.
Selanjutnya kita akan melakukan sedikit update pada halaman category index silahkan teman - teman buka file index.blade.php
yang terletak di dalam folder resources/views/livewire/pages/categories
, kemudian lakukan update pada kode berikut ini :
index.blade.php
<x-button type="create" :href="route('categories.create')">
Pada kode diatas, kita hanya melakukan update pada props href
dengan value route dari categories.create
.
¶Component Category Edit
Tahap ini merupakan tahap terakhir dari pembuatan module category
, disini kita akan lanjutkan untuk membuat sebuah component untuk menghandle update data category. Silahkan teman-teman buka terminal-nya, kemudian jalankan perintah berikut ini :
Terminal
php artisan make:livewire pages.categories.edit
Setelah berhasil menjalankan perintah diatas, kita akan mendapatkan 2 buah file baru yang terletak di :
-
app/Livewire/Pages/Categories/Edit.php
-
resources/views/pages/categories/edit.blade.php
Silahkan teman-teman buka file App/Livewire/Pages/Categories/Edit.php
, kemudian tambahkan kode berikut ini :
Categories/Edit.php
<?php
namespace App\Livewire\Pages\Categories;
use Livewire\Component;
use App\Models\Category;
use Livewire\WithFileUploads;
use Livewire\Attributes\Title;
use Livewire\Attributes\Layout;
class Edit extends Component
{
use WithFileUploads;
// define layout
#[Layout('layouts.app')]
// define title
#[Title('Edit Category')]
// define property
public Category $category;
public $path = 'public/categories/';
public $name;
public $image;
// define lifecycle hooks
public function mount()
{
// assign proprty name with category name
$this->name = $this->category->name;
}
// define valdiation
public function rules()
{
return [
'name' => 'required|string|min:3|max:255|unique:categories,name,'.$this->category->id,
'image' => 'nullable|image|max:2048',
];
}
// define function update
public function update()
{
// call validation
$this->validate();
if($this->image){
// delete old image
Storage::disk('local')->delete($this->path.basename($this->category->image));
// store new image
$this->image->storeAS(path: $this->path, name: $this->image->hashName());
// update category image
$this->category->update([
'image' => $this->image->hashName(),
]);
}
// update category data
$this->category->update([
'name' => $this->name,
'slug' => str()->slug($this->name),
]);
// render view
return $this->redirect('/categories', navigate:true);
}
public function render()
{
// render view
return view('livewire.pages.categories.edit');
}
}
Pada kode diatas pertama - tama, kita menggunakan sebuah trait
yang telah disedikan oleh livewire, trait ini berfungsi sebagai upload file di livewire.
Categories/Edit.php
use WithFileUploads;
Selanjutnya kita mendefinisikan sebuah attribute title
dan layout
.
Categories/Edit.php
// define layout
#[Layout('layouts.app')]
// define title
#[Title('Edit Category')]
Kemudian kita juga mendefinisikan beberapa property diantaranya category
, path
, name
dan image
.
Categories/Edit.php
// define property
public Category $category;
public $path = 'public/categories/';
public $name;
public $image;
Berikutnya kita mendefinisikan sebuah method lifecycle hook didalam livewire yaitu mount
, method ini akan dijalankan ketika component pertama kali dirender.
Categories/Edit.php
// define lifecycle hooks
public function mount()
{
// assign proprty name with category name
$this->name = $this->category->name;
}
Pada kode diatas, kita membuat default value dari property name
mengguakan data dari property category->name
.
Berikutnya kita juga mendefinisikan sebuah validasi, menggunakan method rules
.
Categories/Edit.php
// define valdiation
public function rules()
{
return [
'name' => 'required|string|min:3|max:255|unique:categories,name,'.$this->category->id,
'image' => 'nullable|image|max:2048',
];
}
Method update
Method ini kita gunakan untuk melakukan proses perubahan data tabel categories
kita.
Categories/Edit.php
// define function update
public function update()
{
// call validation
$this->validate();
if($this->image){
// delete old image
Storage::disk('local')->delete($this->path.basename($this->category->image));
// store new image
$this->image->storeAS(path: $this->path, name: $this->image->hashName());
// update category image
$this->category->update([
'image' => $this->image->hashName(),
]);
}
// update category data
$this->category->update([
'name' => $this->name,
'slug' => str()->slug($this->name),
]);
// render view
return $this->redirect('/categories', navigate:true);
}
Didalam method tersebut, pertama - tama kita memangil validasi yang telah kita buat sebelumnya
Categories/Edit.php
// call validation
$this->validate();
kemudian kita melakukan pengecekan dari property image
jika bukan null
maka kita akan menghapus data gambar kategori kita kemudian lakukan upload gambar ulang.
Categories/Edit.php
if($this->image){
// delete old image
Storage::disk('local')->delete($this->path.basename($this->category->image));
// store new image
$this->image->storeAS(path: $this->path, name: $this->image->hashName());
// update category image
$this->category->update([
'image' => $this->image->hashName(),
]);
}
Kemudian jika request yang kita kirimkan sudah sesuai dengan kriteria validasi yang kita definisikan, maka kita lakukan update data tabel categories
sesuai dengan id menggunakan method update
.
Categories/Edit.php
// update category data
$this->category->update([
'name' => $this->name,
'slug' => str()->slug($this->name),
]);
Terakhir kita akan diarahkan ke sebuah route yang bernama categories.index
, disini kita memanfaat redirect dari livewire navigate true
yang artinya kita akan berpindah halaman tanpa melakukan reload page.
Categories/Edit.php
// render view
return $this->redirect('/categories', navigate:true);
Method Render
Method ini kita gunakan untuk menampilkan sebuah halaman create data category.
Categories/Edit.php
public function render()
{
// render view
return view('livewire.pages.categories.edit');
}
Pada kode diatas kita hanya mengembalikan sebuah view dengan nama livewire.pages.categories.edit
.
Categories/Edit.php
// render view
return view('livewire.pages.categories.edit');
¶Route Component Category Edit
Setelah berhasil membuat component category edit, 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 Illuminate\Support\Facades\Route;
use App\Livewire\Pages\Categories\Index as CategoryIndex;
use App\Livewire\Pages\Categories\Create as CategoryCreate;
use App\Livewire\Pages\Categories\Edit as CategoryEdit;
Route::view('/', 'welcome');
Route::group(['middleware' => ['auth']], function(){
// categories route
Route::group(['prefix' => 'categories', 'as' => 'categories.'], function(){
Route::get('/', CategoryIndex::class)->name('index');
Route::get('/create', CategoryCreate::class)->name('create');
Route::get('/edit/{category}', CategoryEdit::class)->name('edit');
});
});
Route::view('dashboard', 'dashboard')
->middleware(['auth', 'verified'])
->name('dashboard');
Route::view('profile', 'profile')
->middleware(['auth'])
->name('profile');
require __DIR__.'/auth.php';
Dari perubahan kode diatas, kita menambahkan sebuah route baru dengan nama categories/edit/{category}
jika teman-teman perhatikan pada route edit, disini kita menggunakan jenis route model binding
, untuk memastikan route yang kita buat berfungsi, teman - teman bisa jalankan perintah berikut ini dalam terminal.
Terminal
php artisan r:l --name=categories
Setelah perintah artisan diatas berhasil dijalankan maka kita akan mendapatkan output, kurang lebih seperti berikut ini.
Terminal
GET|HEAD categories .......................................... categories.index › App\Livewire\Pages\Categories\Index
GET|HEAD categories/create ................................. categories.create › App\Livewire\Pages\Categories\Create
GET|HEAD categories/edit/{category} ............................ categories.edit › App\Livewire\Pages\Categories\Edit
¶View Component Category Edit
Setelah berhasil membuat route untuk penambahan data category, disini akan kita lanjutkan untuk pembuatan view ubaw data category. silahkan teman - teman buka file yang bernama edit.blade.php
yang terletak di resources/views/livewire/pages/categories
, kemudian tambahkan kode berikut ini :
edit.blade.php
<div>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Edit Category') }}
</h2>
</x-slot>
<div class="py-12 px-4">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<x-card title="Edit Category">
<form wire:submit.prevent="update">
<div class="mb-4">
<x-input type="text" label="Category Name" name="name" :value="old('name')" placeholder="Enter a category name..."/>
</div>
<div class="mb-4">
<x-input label="Category Image" type="file" name="image"/>
</div>
<div class="flex items-center gap-2">
<x-button type="submit" title="Update Category"/>
<x-button type="cancel" title="Go Back" :href="route('categories.index')"/>
</div>
</form>
</x-card>
</div>
</div>
</div>
Pada kode diatas, kita melakukan pemanggilan beberapa components yang telah kita buat sebelumnya diantaranya :
-
<x-card/>
- props yang digunakan title
-
<x-button/>
- props yang digunakan type
, href
dan title
.
-
<x-input/>
- props yang digunakan type
, label
, name
, value
dan placeholder
.
Pada bagian form action
kita menggunakan attribute yang disediakan oleh livewire yaitu wire:submit.prevent
kemudian kita set valuenya dengan method update
yang telah kita buat sebelumnya.
Selanjutnya kita akan melakukan sedikit update pada halaman category index , silahkan teman - teman buka file index.blade.php
yang terletak di dalam folder resources/views/livewire/pages/categories
, kemudian lakukan update pada kode berikut ini :
index.blade.php
<x-button type="edit" title="Edit" :href="route('categories.edit', $category->id)"/>
Pada kode diatas, kita hanya melakukan update props href
dengan value route dari categories.edit
.
¶Screenshoot Hasil
¶Penutup
Pada artikel kali ini kita telah berhasil menyelesaikan pembuatan module category, selanjutnya kita akan lanjutkan untuk pembuatan module product.