Dropdown list with Laravel and Select 2

Dropdown list with Laravel and Select 2

Select 2 is a handy replacement for the native HTML select input which comes with a limited set of features. Specially its a pain to work with native select input when you want loading options dynamically from the server side. Let’s see how we can improve your dropdown selector experience a bit with Select 2 and Laravel.

Dynamic options loading for HTML <select>

First of all let’s see how we can load options programmatically into a native select box. In this case we have search box, where we are going to type our search words and a select box, where the dynamic list of options will be loaded.

<input type="text" id="search" placeholder="Type to search" />
<select id="country-selector"></select>

You may use jQuery to load options.

<script type="text/javascript">
  $(document).ready(function($) {
    $('#search').on('keyup', function() {
      var query = $(this).val();

      if (query != '') {
        $.ajax({
          url: '/countries/json',
          data: 'search=' + query,
          success: function(data) {
            if (data.length) {
              $.each(data, function(index, country) {
                var option = $('<option>').attr('value', country.code).text(country.name);
                $('#country-selector').append(option);
              });
            }
          }
        });
      }
    });
  });
</script>

To support this our server side code should accept a search query and return the matching list of countries in JSON format.

[
  {"code": "AE", "name": "United Arab Emirates"},
  {"code": "GB", "name": "United Kingdom"},
  {"code": "US", "name": "United States"}
]

Filter and output data in JSON format with Laravel

Let’s see how we can get the country list from the server side when Laravel is our backend. We have the country list in countries table. And Country model is the respective model class.

<?php

namespace App\Entities;

use Illuminate\Database\Eloquent\Model;

class Country extends Model
{
    protected $table = 'countries';

    protected $fillable = [
        'code',
        'name',
    ];
}

We need to add a route to routes/web.php to get countries list. This is the route we call to load the filtered list of countries.

Route::get('/countries/json', 'CountryController@json');

Create file app/Http/Controllers/CountryController and add json() action (function).

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Entities\Country;
use App\Http\Controllers\Controller;

class CountryController extends Controller
{
    /**
     * Returns the list of countries in json format.
     *
     * @param \Illuminate\Http\Request $request
     * @return \Illuminate\Http\Response
     */
    public function json(Request $request)
    {
        // get only 20 items at a time
        $countriesQuery = Country::limit(20);

        // filter countries according to the search words
        $search = $request->query('search');
        if ($search) {
            $countriesQuery->where('name', 'LIKE', '%' . $search . '%');
        }

        $countries = $countriesQuery->get();

        return response()->json($countries);
    }
}

Now, that’s how to get options dynamically loaded into the HTML select input.

Great, then why do we need Select 2?

If you tried above code to dynamically fill <select> with options, you might notice that its not smooth and it kills the entire UX. And more or less that’s all you can do with HTML <select>. Let’s try Select 2 for a better experience.

This time we don’t need the <input> element for searching.

<select id="country-selector"></select>

In order to get Select 2 on your page you need to add two files. Add Select 2 stylesheet within <head> & </head> tags.

<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.9/css/select2.min.css" rel="stylesheet" />

And, add Select 2 JavaScript file just before the </body>. Make sure you have loaded jQuery before Select 2.

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<script type="text/javascript">
  jQuery(document).ready(function() {
    $('#country-selector').select2({
      placeholder: 'Start typing to search',
      ajax: {
        url: '/countries/json',
        data: function(params) {
          var query = {
            search: params.term,
          };

          return query;
        },
        processResults: function(data) {
          var results = [];
          if (data.length) {
            $.each(data, function(index, country) {
              results.push({
                id: country.code,
                text: country.name
              });
            });
          }

          return {
            results: results
          };
        }
      }
    });
  });    
</script>

That’s it. Give it a try.

Read Select 2 documentation for more features and options.

Saranga
Saranga A web developer and highly passionate about research and development of web technologies around PHP, HTML, JavaScript and CSS.
comments powered by Disqus