When building interactive forms in Laravel applications, dependent dropdowns — where the options in one dropdown depend on the selection of another — are a common requirement.
For example, when a user selects a country, the city dropdown should update accordingly.
There are two popular ways to implement this:
- The AJAX way (using JavaScript and API routes)
- The Livewire way (pure PHP, reactive and modern)
Let’s explore both, compare them, and highlight when each approach shines.
🧪 Use Case: Country ➡ City Dropdown
Imagine a scenario in a travel booking system:
- User selects a country
- The system displays a list of cities based on that country
1. 💻 The AJAX Approach
Traditionally, developers used jQuery or plain JavaScript to send an AJAX request when the first dropdown changes. The backend returns city data in JSON, and JavaScript dynamically populates the second dropdown.
Sample Setup
<!-- Country Dropdown -->
<select id="country">
<option value="MY">Malaysia</option>
<option value="TH">Thailand</option>
</select>
<!-- City Dropdown -->
<select id="city"></select>
<script>
$('#country').on('change', function() {
let country = $(this).val();
$.get('/api/cities/' + country, function(data) {
$('#city').empty();
$.each(data, function(index, city) {
$('#city').append(`<option value="${city.id}">${city.name}</option>`);
});
});
});
</script>
2. ⚡ The Livewire Approach (No JavaScript, No API)
Laravel Livewire simplifies this entire flow — you can handle dependent dropdowns using only PHP and Blade, no need to write JS or expose any API routes.
How it Works
- The
country
dropdown is bound usingwire:model.live
- When the value changes, Livewire updates the
cities
list in real-time - All logic lives inside a Livewire component
Sample Livewire Component (Simplified)
class LocationSelector extends Component
{
public $country;
public $city;
public $cities = [];
public $allCities = [
'MY' => [
['id' => 'KUL', 'name' => 'Kuala Lumpur'],
['id' => 'PG', 'name' => 'Penang'],
],
'TH' => [
['id' => 'BKK', 'name' => 'Bangkok'],
['id' => 'CNX', 'name' => 'Chiang Mai'],
],
];
public function updatedCountry($value)
{
$this->city = null;
$this->cities = $this->allCities[$value] ?? [];
}
public function render()
{
return view('livewire.location-selector');
}
}
Corresponding Blade View
<select wire:model.live="country">
<option value="">Select Country</option>
<option value="MY">Malaysia</option>
<option value="TH">Thailand</option>
</select>
@if (!empty($cities))
<select wire:model="city">
<option value="">Select City</option>
@foreach ($cities as $city)
<option value="{{ $city['id'] }}">{{ $city['name'] }}</option>
@endforeach
</select>
@endif
Absolutely! Here's a combined Pros and Cons section that directly compares AJAX and Livewire for handling dynamic dependent dropdowns:
⚖️ AJAX vs Livewire: Pros & Cons
Feature / Factor | ✅ Livewire | ✅ AJAX (jQuery / JS) |
---|---|---|
🧠 Ease of Implementation | Straightforward — everything in PHP/Blade, no need to write JS | Requires JavaScript, route/controller setup, and JSON handling |
🔁 Reactivity / Real-time Updates | Built-in reactivity using wire:model.live
|
Requires manual event binding and DOM manipulation |
🌐 API / Data Layer | No API needed — uses internal component state | Needs a dedicated API endpoint and possibly middleware |
🧪 Testability | Easy to write tests using Livewire component testing | API needs to be tested separately from the JS layer |
🔧 Flexibility / Control | Works great for simple to moderate use cases | More flexible for advanced, frontend-heavy interactivity |
🧩 Reusability | Tight coupling with Livewire views — not easily reusable outside Laravel | API approach is reusable for Vue, mobile apps, or other consumers |
⚙️ Debugging | Debuggable within PHP stack, fewer moving parts | More complex — inspect console/network tab, deal with async issues |
🧱 Learning Curve | Simple if already using Laravel + Livewire | Familiar to most developers with basic JavaScript knowledge |
🚀 Performance | Can be slower with many components or heavy DOM updates | Faster client-side rendering once data is fetched |
🔒 Security | Automatically handles CSRF, session state via Laravel | Must handle CSRF, headers, and auth on the client manually |
🎯 When to Use Which?
Situation | Best Choice |
---|---|
You need fast interactivity | Livewire |
You’re building with full-stack JS | AJAX (or Vue/Alpine) |
You need to reuse the API elsewhere | AJAX |
You want less boilerplate & faster prototyping | Livewire |
🔚 Conclusion
If you’re already using Laravel Livewire, dependent dropdowns can be handled 100% in PHP with minimal effort.
It leads to cleaner code, faster prototyping, and fewer moving parts.
But if you’re exposing the same data to a frontend framework, mobile app, or need caching layers, the AJAX + API route might still be the more scalable approach.
Both are valid.
Choose the one that fits your project scale, team expertise, and desired maintainability.
📌 Which method do you prefer for dynamic dropdowns? Let me know in the comments!
Photo by Reuben Mergard on Unsplash
Top comments (0)