In last post we used pure JavaScript with Axios in order to get dependent dropdown (dynamic select menu) feature in a Laravel 9 app. Apparently, the code seemed a bit of mess while using pure JavaScript to make Ajax calls and generate HTML elements on the fly. Now, let’s employ Vue as in VILT (Vue Inertia Lavarel Tailwind) stack for Laravel 9 to achieve the same behavior of dependent dropdown / dynamic select menu, but with a bit more elegance.
For this article we’ll utilize the models and data created in a previous article. So, first follow the steps given there for creating models, migrations, and relationship and then continue from here.
By following the above-mentioned article, we now have a couple of tables (customers and invoices) having one-to-many relationship along with test data; so, let’s continue and add Breeze package by executing following command in project’s parent folder;
composer require laravel/breeze:* --dev
Then, install Breeze with Vue by executing following command;
php artisan breeze:install vue
Next, execute following command in parent folder to create InvoiceController.php;
php artisan make:controller InvoiceController
Open app/Http/Controllers/InvoiceController.php and amend it as follows;
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Invoice;
use App\Models\Customer;
use Inertia\Inertia;
class InvoiceController extends Controller
{
public function index(Request $request)
{
$customers = Customer::all();
$invoices = [];
$selectedInvoice = null;
if($request->input('customer')){
$invoices = Invoice::where('customer_id', $request->input('customer'))->get();
session(['selectedCustomer' => $request->input('customer')]);
}
if($request->input('invoice')){
$invoices = Invoice::where('customer_id', session('selectedCustomer'))->get();
$selectedInvoice = Invoice::where('id', $request->input('invoice'))->get()
->map(function ($item, $key) {
return [
'invoice_number' => $item->invoice_number,
'invoice_date' => $item->invoice_date,
'name' => $item->customer->name,
'address' => $item->customer->address,
'description' => $item->description,
'amount' => $item->amount,
];
})[0];
}
return Inertia::render('Index', ['customers' => $customers, 'invoices' => $invoices, 'selectedInvoice' => $selectedInvoice]);
}
}
Next, open routes/web.php and put the following line at the upper side of it;
use App\Http\Controllers\InvoiceController;
And then insert following new route in this routes/web.php as given below;
Route::get('/invoices', [InvoiceController::class, 'index'])->name('invoices');
Now, we are all set to create our Vue file. So, create Index.vue file by entering following command in project’s parent folder:
touch resources/js/Pages/Index.vue
Then, insert following code inside resources/js/Pages/Index.vue:
<template>
<div>
<div class="m-4 flex flex-col">
<label class="">Select Customer:</label>
<select class="w-60" @change="changeCustomer($event)" >
<option value="">Please select customer</option>
<option v-for='item in customers' :value='item.id' :key='item.id'>{{ item.name }}</option>
</select>
</div>
<div class="m-4 flex flex-col">
<label class="">Select Invoice:</label>
<select class="w-60" @change="changeInvoice($event)" >
<option value="">Please select invoice</option>
<option v-for='item in invoices' :value='item.id' :key='item.id'>{{ item.invoice_number }}</option>
</select>
</div>
<div v-if="selectedInvoice" class="m-4 flex flex-col">
<table class="border border-black">
<tr><td>Invoice Ref:</td><td> {{selectedInvoice.invoice_number}} </td></tr>
<tr><td>Invoice Date:</td><td> {{selectedInvoice.invoice_date}} </td></tr>
<tr><td>Customer Name:</td><td> {{selectedInvoice.name}} </td></tr>
<tr><td>Customer Address:</td><td> {{selectedInvoice.address}} </td></tr>
<tr><td>Description:</td><td> {{selectedInvoice.description}} </td></tr>
<tr><td>Amount:</td><td> {{selectedInvoice.amount}} </td></tr>
</table>
</div>
</div>
</template>
<script setup>
import { router } from '@inertiajs/vue3';
defineProps({
customers : Object,
invoices : Object,
selectedInvoice : Object,
})
const changeCustomer = (event) => {
router.get(route('invoices'), {customer: event.target.value}, {preserveState: true});
}
const changeInvoice = (event) => {
router.get(route('invoices'), {invoice: event.target.value}, {preserveState: true});
}
</script>
Finally, execute the following command to compile the UI assets:
npm run build
Run PHP development server by executing;
php artisan serv
Open browser and enter the following URL;
http://localhost:8000/invoices