Laravel
Select dinámicos en Laravel solo con JS
6 abril, 2025
•
19,232 lecturas
Etiquetas:
#Selects Dependientes
¿Cómo implementar select dependientes en Laravel?
En este caso programaremos un ejemplo de Selects dependientes de tres niveles con la API Fetch de JS y Laravel. Para ello, antes se usaba comunmente Jquery, hoy en dia contamos con una solución nativa que requiere de menos líneas de código y la mayoría de navegadores modernos ya lo soportan. Entonces:
- Solo usaremos Javascript donde vamos a consumir la API Fetch para inflar los select dinámicamente.
- El framework Laravel - PHP para el desarrollo de aplicaciones web
- HTML y CSS para maquetar es decir aplicar diseño a la vista.
Estructura de la Base de Datos
Asumiremos que tienes las tablas:
categories(id, name)subcategories(id, category_id, name)products(id, subcategory_id, name)
Modelos y Relaciones
Define las relaciones en los modelos:
php
// Category.php
public function subcategories() {
return $this->hasMany(Subcategory::class);
}
// Subcategory.php
public function category() {
return $this->belongsTo(Category::class);
}
public function products() {
return $this->hasMany(Product::class);
}
// Product.php
public function subcategory() {
return $this->belongsTo(Subcategory::class);
}
Rutas (routes/web.php)
Crea rutas: web y para las peticiones AJAX:
php
Route::get('categories', [FrontController::class,'getCategories']);
Route::get('/subcategories/{category}', [FrontController::class, 'getSubcategories']);
Route::get('/products/{subcategory}', [FrontController::class, 'getProducts']);
Controladores
Crea los métodos para devolver datos en formato JSON:
php
public function getCategories(){
$categories = Category::all();
return view('categoria', compact("categories"));
}
public function getSubcategories(Category $category){
return response()->json($category->subcategories);
}
public function getProducts(Subcategory $subcategory) {
return response()->json($subcategory->products);
}
Vista Blade (HTML + JavaScript)
Crea el formulario con selects dependientes:
blade
<h1 class="text-3xl underline p-5 text-center">SELECT DEPENDIENTES</h1>
<div class="flex justify-center">
<div class="grid grid-cols-3 w-3/4 gap-10">
<select id="category" class="border rounded-lg p-2">
<option value="">Selecciona una categoría</option>
@foreach ($categories as $category)
<option value="{{ $category->id }}">{{ $category->name }}</option>
@endforeach
</select>
<select id="subcategory" class="border rounded-lg p-2" disabled>
<option value="">Selecciona una subcategoría</option>
</select>
<select id="product" class="border rounded-lg p-2" disabled>
<option value="">Selecciona un producto</option>
</select>
</div>
</div>
JavaScript (Vanilla JS)
Agrega el script para manejar las dependencias:
javascript
document.getElementById('category').addEventListener('change', function() {
const categoryId = this.value;
const subcategorySelect = document.getElementById('subcategory');
const productSelect = document.getElementById('product');
// Resetear selects
subcategorySelect.innerHTML = '<option value="">Selecciona una subcategoría</option>';
subcategorySelect.disabled = true;
productSelect.innerHTML = '<option value="">Selecciona un producto</option>';
productSelect.disabled = true;
if (categoryId) {
// Cargar subcategorías
fetch(`/subcategories/${categoryId}`)
.then(response => response.json())
.then(data => {
subcategorySelect.innerHTML = data.map(item =>
`<option value="${item.id}">${item.name}</option>`
).join('');
subcategorySelect.disabled = false;
});
}
})
document.getElementById('subcategory').addEventListener('change', function() {
const subcategoryId = this.value;
const productSelect = document.getElementById('product');
// Resetear productos
productSelect.innerHTML = '<option value="">Selecciona un producto</option>';
productSelect.disabled = true;
if (subcategoryId) {
// Cargar productos
fetch(`/products/${subcategoryId}`)
.then(response => response.json())
.then(data => {
productSelect.innerHTML = data.map(item =>
`<option value="${item.id}">${item.name}</option>`
).join('');
productSelect.disabled = false;
});
}
});document.getElementById('category').addEventListener('change', function() {
const categoryId = this.value;
const subcategorySelect = document.getElementById('subcategory');
const productSelect = document.getElementById('product');
// Resetear selects
subcategorySelect.innerHTML = '<option value="">Selecciona una subcategoría</option>';
subcategorySelect.disabled = true;
productSelect.innerHTML = '<option value="">Selecciona un producto</option>';
productSelect.disabled = true;
if (categoryId) {
// Cargar subcategorías
fetch(`/subcategories/${categoryId}`)
.then(response => response.json())
.then(data => {
subcategorySelect.innerHTML = data.map(item =>
`<option value="${item.id}">${item.name}</option>`
).join('');
subcategorySelect.disabled = false;
});
}
})
document.getElementById('subcategory').addEventListener('change', function() {
const subcategoryId = this.value;
const productSelect = document.getElementById('product');
// Resetear productos
productSelect.innerHTML = '<option value="">Selecciona un producto</option>';
productSelect.disabled = true;
if (subcategoryId) {
// Cargar productos
fetch(`/products/${subcategoryId}`)
.then(response => response.json())
.then(data => {
productSelect.innerHTML = data.map(item =>
`<option value="${item.id}">${item.name}</option>`
).join('');
productSelect.disabled = false;
});
}
});document.getElementById('category').addEventListener('change', function() {
const categoryId = this.value;
const subcategorySelect = document.getElementById('subcategory');
const productSelect = document.getElementById('product');
// Resetear selects
subcategorySelect.innerHTML = '<option value="">Selecciona una subcategoría</option>';
subcategorySelect.disabled = true;
productSelect.innerHTML = '<option value="">Selecciona un producto</option>';
productSelect.disabled = true;
if (categoryId) {
// Cargar subcategorías
fetch(`/subcategories/${categoryId}`)
.then(response => response.json())
.then(data => {
subcategorySelect.innerHTML = data.map(item =>
`<option value="${item.id}">${item.name}</option>`
).join('');
subcategorySelect.disabled = false;
});
}
})
document.getElementById('subcategory').addEventListener('change', function() {
const subcategoryId = this.value;
const productSelect = document.getElementById('product');
// Resetear productos
productSelect.innerHTML = '<option value="">Selecciona un producto</option>';
productSelect.disabled = true;
if (subcategoryId) {
// Cargar productos
fetch(`/products/${subcategoryId}`)
.then(response => response.json())
.then(data => {
productSelect.innerHTML = data.map(item =>
`<option value="${item.id}">${item.name}</option>`
).join('');
productSelect.disabled = false;
});
}
});
¿Cómo funciona?
- Al seleccionar una categoría , se hace una petición GET a
/subcategories/{category}para obtener las subcategorías asociadas. - Al seleccionar una subcategoría , se hace una petición GET a
/products/{subcategory}para obtener los productos. - Los selects se habilitan/deshabilitan según la selección anterior.
Tutoriales Recomendados
Sigue explorando publicaciones de la misma categoría