Inicio » Blog »

6 abril, 2025

Select dinámicos en Laravel solo con JS

#Javascript #Laravel #MySql #PHP #Selects Dependientes

Para implementar select dependientes en Laravel necesitamos tres modelos, la API nativa Fetch de Javascript para realizar la peticiones mediante promesas.

Select dinámicos en Laravel solo con JS

Suscríbete a nuestro canal en Youtube

Suscríbirse

¿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?

  1. Al seleccionar una categoría , se hace una petición GET a /subcategories/{category} para obtener las subcategorías asociadas.
  2. Al seleccionar una subcategoría , se hace una petición GET a /products/{subcategory} para obtener los productos.
  3. Los selects se habilitan/deshabilitan según la selección anterior.

Leido 17776 veces | 10 usuarios

Descarga del código fuente Laravel de Select dinámicos en Laravel solo con JS

Accede al código fuente esencial de nuestra aplicación en formato ZIP ó TXT. Ideal para desarrolladores que desean personalizar o integrar nuestra solución.

Opciones de descarga

  • Usuarios Registrados: Inicia sesión para descarga inmediata.
  • Nuevos Usuarios: Regístrate y descarga.

99 descargas

Para descargar el código inicia sesión o crea una cuenta

Iniciar Sesión

Compartir link del tutorial con tus amigos

Cuestionario de 15 preguntas sobre la implementación de selects dependientes en Laravel

Aquí tienes un cuestionario de 15 preguntas en formato JSON basado en el contenido proporcionado sobre la implementación de selects dependientes en Laravel :

1. ¿Qué API se utiliza para manejar las peticiones asíncronas en este ejemplo?

2. ¿Qué tipo de relaciones se definen entre los modelos Category y Subcategory?

3. ¿Qué ruta se utiliza para obtener las subcategorías asociadas a una categoría?

4. ¿Qué método del modelo Category retorna las subcategorías relacionadas?

5. ¿Qué función cumple el evento 'change' en el select de categorías?

6. ¿Qué estructura HTML se utiliza para crear los selects dependientes?

7. ¿Qué método del controlador se utiliza para devolver las subcategorías en formato JSON?

8. ¿Qué hace el método 'resetear' en los selects dependientes?

9. ¿Qué tipo de respuesta retorna el método 'getProducts' del controlador?

10. ¿Qué atributo HTML se usa para deshabilitar un select hasta que se seleccione una opción válida?

11. ¿Qué método HTTP se utiliza para obtener las subcategorías y productos en este ejemplo?

12. ¿Qué herramienta o framework NO es necesario usar en esta implementación básica?

13. ¿Qué relación define el modelo Product con el modelo Subcategory?

14. ¿Qué archivo Blade contiene la vista principal donde se muestran los selects dependientes?

15. ¿Qué diseño CSS se utiliza para organizar los selects en columnas?


ReactJS y Laravel Directorio de Empresas

USD 17.00

Descarga del código fuente

ReactJS y Laravel Directorio de Empresas
Curso de Laravel básico

USD 0.00

Descarga del código fuente

Curso de Laravel básico
Laravel Página Web Administrable

USD 37.00

Descarga del código fuente

Laravel Página Web Administrable

Codea Applications

México, Colombia, España, Venezuela, Argentina, Bolivia, Perú