select2-laravel-ajax

El plugin Select2 de JQuery permite crear campos de tipo «select» en nuestros formularios con la habilidad de agregar ciertas funcionalidades como búsqueda en tiempo real, etiquetas y algunas otras opciones realmente útiles.

Hoy vamos a implementar Select2 en Laravel usando JQuery y Ajax para buscar y cargar etiquetas de forma dinámica en un campo de texto.

Configuración de base de datos

Vamos a cargar algunas etiquetas dentro de una tabla en nuestra base de datos. De esta manera podremos consultar y obtener estos valores de forma dinámica usando Ajax.

Una vez creada la base de datos agrega las credenciales correspondientes al archivo .env

DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=my_database
DB_USERNAME=homestead
DB_PASSWORD=secret

Creamos un nuevo modelo llamado Tag desde la consola con:

$ php artisan make:model Tag

Y editamos su contenido agregando los atributos $table y $fillable de la siguiente manera:

class Tag extends Model
{
    protected $table = 'tags';

    protected $fillable = ['name'];
}

Creamos una nueva migración para construir la tabla que contendrá las etiquetas. Esto lo hacemos desde la consola con:

$ php artisan make:migration create_tags_table
<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateTagsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('tags', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('tags');
    }
}

También podemos crear un seeder para agregar algunos tags de prueba a la base de datos.

$ php artisan make:seeder TagsTableSeeder

Y editamos el archivo databse/seeds/TagsTableSeeder de la siguiente manera:

<?php

use Illuminate\Database\Seeder;
use App\Tag;

class TagsTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        Tag::create(['name' => 'PHP']);
        Tag::create(['name' => 'MySql']);
        Tag::create(['name' => 'Javascript']);
        Tag::create(['name' => 'Laravel']);
        Tag::create(['name' => 'Css']);
    }
}

Recuerda que para crear datos de prueba también puedes hacer uso de los model factories: Model factories en Laravel 5.1

Ahora debemos llamar a esta clase TagsTableSeeder en el archivo DatabaseSeeder:

<?php

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $this->call(TagsTableSeeder::class);
    }
}

Finalmente para aplicar estos cambios a la base de datos ejecutamos lo siguiente desde la consola:

$ php artisan migrate --seed

Instalación y configuración de Select2

Lo primero que debemos hacer es descargar el plugin desde el sito oficial: https://select2.github.io/

Una vez descargado, abrimos el archivo comprimido descargado y extraemos el contenido de la carpeta dist/ al directorio public de nuestra aplicación de Laravel.

|-Public
|----css
|--------select2.css
|--------select2.min.css
|----js
|--------i18n
|--------select2.full.js
|--------select2.full.min.js
|--------select2.js
|--------select2.min.js

Creamos una vista que incluya los archivos del plugin dentro de resources/views/layout.blade.php

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Laravel</title>
    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.4.0/css/font-awesome.min.css" rel='stylesheet' type='text/css'>
    <link href="https://fonts.googleapis.com/css?family=Lato:100,300,400,700" rel='stylesheet' type='text/css'>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet">
    <link href="/css/select2.min.css" rel="stylesheet">
</head>
<body id="app-layout">
    
    <div class="container">
        @yield('content')
    </div>

    <!-- JavaScripts -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
    <script src="js/select2.min.js"></script>
    @yield('scripts')
</body>
</html>

Ésta será la plantilla o layout base para la vista del formulario, aquí incluimos el CDN de Bootstrap.

Creamos una nueva vista que contiene el formulario con el campo para las etiquetas llamada form.blade.php

@extends('layout')

@section('content')
<div class="col-md-10 col-md-offset-1">
    <form name="test-form" method="POST" action="#">

        <div class="form-group">
            <label for="tags" class="control-label">Tags</label>
            <select name="tags[]" class="form-control" multiple="multiple" id="tags"></select>
        </div>

    </form>
</div>
@endsection

@section('scripts')
<script type="text/javascript">
    $(document).ready(function () {
        // inicializamos el plugin
        $('#tags').select2({
            // Activamos la opcion "Tags" del plugin
            tags: true,
            tokenSeparators: [','],
            ajax: {
                dataType: 'json',
                url: '{{ url("tags") }}',
                delay: 250,
                data: function(params) {
                    return {
                        term: params.term
                    }
                },
                processResults: function (data, page) {
                  return {
                    results: data
                  };
                },
            }
        });
    });
</script>
@endsection

El nombre del campo es tags[], esto permite que todos los valores se envíen dentro de un array «tags»

Ahora necesitaremos una ruta para acceder a este formulario, dentro del archivo app\Http\routes.php agregamos lo siguiente:

Route::get('form', function () {
    return view('form');
});

Si tratamos de ingresar a url_del_proyecto/form vamos a obtener un error, debido a que no hemos creado la ruta «tags» que estamos usando dentro de la configuración del plugin select2.

url: '{{ url("tags") }}',

Vamos a crear esta ruta «tags»

    Route::get('tags', function (Illuminate\Http\Request  $request) {
        $term = $request->term ?: '';
        $tags = App\Tag::where('name', 'like', $term.'%')->lists('name', 'id');
        $valid_tags = [];
        foreach ($tags as $id => $tag) {
            $valid_tags[] = ['id' => $id, 'text' => $tag];
        }
        return \Response::json($valid_tags);
    });

El plugin Select2 espera la data para llenar el campo con el siguiente formato:

[{'id': 00, 'text' => 'tag-name' }]

Es por este motivo que se crea un nuevo array llamado $valid_tags en el bloque anterior.

Resultado

Finalmente si ingresas a url_del_proyecto/form tendrás un campo para agregar etiquetas con autocompletado usando Ajax.

Capture

Ejercicios

Este es apenas un ejemplo sencillo para mostrarte una de las ventajas de este plugin, pero aún faltan algunos detalles para hacer de este ejemplo un feature totalmente funcional. Esto es lo que puedes hacer para completar esta tarea:

  1. Agrega una controlador que capture el formulario y reciba el listado de tags.
  2. Si un tag no existe en la base de datos debería poder almacenarse.
  3. No se deben guardar Tags repetidos en la base de datos.

¿Necesitas ayuda?

Cada uno de los temas mencionados en la sección de ejercicios se explican con detalle en nuestro curso Curso de interfaces dinámicas con Laravel y jQuery. Si quieres aprender a crear aplicaciones de forma profesional y aprender a integrar diferentes herramientas de JQuery con Laravel, Registrate al curso ahora mismo y mejora tus habilidades como programador, te esperamos.

Esto ha sido todo por ahora, si te animas a resolver los ejercicios planteados puedes dejar tus resultados en la sección de comentarios, de igual manera si tienes una duda puedes plantearla allí.

Regístrate hoy en Styde y obtén acceso a todo nuestro contenido.

Lección anterior Cómo generar vista previa de los correos con Laravel Lección siguiente Editar archivos Sass en Laravel con Chrome Developer Tools