Laravel 7 autopopulate dropdown using Ajax

Laravel 7 autopopulate dropdown using Ajax

Todays tutorial will be on how to auto-populate a dropdown according to a preselected dropdown on Laravel using Ajax.

This tutorial is also available on github.

First of all, we’ll create a new Laravel project(I’m assuming you already have composer installed).You could call the project anything but I’ll just go with “autopopulate”.

composer create-project laravel/laravel autopopulate

Then open the .env file and adjust the database connection settings to match your database name and credentials.

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=autopopulate
DB_USERNAME=root
DB_PASSWORD=

For this tutorial, I’m going to using Countries and States.

Let’s create out model and migrations file for both.

Run

php artisan make:model Country -m

and then run

php artisan make:model State -m

For the country migrations file.

Schema::create(
    'countries',
    function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->timestamps();
    }
);

For the state migrations file.

Schema::create(
    'states',
    function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->integer('country_id');
        $table->timestamps();
    }
);

We will create dummy data for both in our database.

Let’s create our factories for both.

Run

php artisan make:factory CountryFactory

and then run

php artisan make:factory StateFactory

For the country factory

<?php

/** @var \Illuminate\Database\Eloquent\Factory $factory */

use App\Country;
use Faker\Generator as Faker;

$factory->define(
    Country::class,
    function (Faker $faker) {
        return [
            'name' => $faker->word
        ];
    }
);

For the state factory

<?php

/** @var \Illuminate\Database\Eloquent\Factory $factory */

use App\State;
use Faker\Generator as Faker;

$factory->define(
    State::class,
    function (Faker $faker) {
        return [
            'name' => $faker->word
        ];
    }
);

In the database seeder

<?php

use App\Country;
use App\State;
use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        $countries =  factory(Country::class, 20)->create();
        $countries->each(
            function ($country) {
                factory(State::class, 35)->create(['country_id' => $country->id]);
            }
        );
    }
}

Then run

php artisan migrate

and run

php artisan db:seed

At this point, your database has been populate with dummy data.

Then let’s create our controller to handle all our requests.

You can give your controller any name that suits your project

php artisan make:controller HomeController

Open your web.php file to register routes

Route::get('/', 'HomeController@index');
Route::get('/state/{countryId}', 'HomeController@getState');

In your Controller

<?php

namespace App\Http\Controllers;

use App\Country;
use App\State;

class HomeController extends Controller
{
    /**
     * Display page with all countries
     *
     * @return Illuminate\View\View
     * @author Anthony Akro <anthonygakro@gmail.com> [a4anthony]
     */
    public function index()
    {
        $countries = Country::all();
        return view('welcome', ['countries' => $countries]);
    }
    /**
     * Retrieves state details from database
     *
     * @param int $countryId
     *
     * @return Illuminate\Http\Response
     * @author Anthony Akro <anthonygakro@gmail.com> [a4anthony]
     */
    public function getState($countryId)
    {
        if (!$countryId) {
            $html = '<option value="">' . trans('global.pleaseSelect') . '</option>';
        } else {
            $html = '<option value="' . '">' . '--- Select Sub Category ---' . '</option>';
            $states = State::where('country_id', $countryId)->get();

            foreach ($states as $state) {
                $html .= '<option value="' . $state->id . '">' . $state->name . '</option>';
            }
        }

        return response()->json(['html' => $html]);
    }
}

In your welcome.blade.php file in the the Resources > view folder

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>Laravel Autopopulate</title>

    <!-- Fonts -->
    <link href="https://fonts.googleapis.com/css?family=Nunito:200,600" rel="stylesheet">

    <!-- jquery -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>

    <!-- bootstrap -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>

    <!-- Styles -->
    <style>
        html,
        body {
            background-color: #fff;
            color: #636b6f;
            font-family: 'Nunito', sans-serif;
            font-weight: 200;
            height: 100vh;
            margin: 0;
        }

        .full-height {
            height: 100vh;
        }

        .flex-center {
            align-items: center;
            display: flex;
            justify-content: center;
        }

        .position-ref {
            position: relative;
        }

        .top-right {
            position: absolute;
            right: 10px;
            top: 18px;
        }

        .content {
            text-align: center;
        }

        .title {
            font-size: 84px;
        }

        .links>a {
            color: #636b6f;
            padding: 0 25px;
            font-size: 13px;
            font-weight: 600;
            letter-spacing: .1rem;
            text-decoration: none;
            text-transform: uppercase;
        }

        .m-b-md {
            margin-bottom: 30px;
        }
    </style>
</head>

<body>
    <div class="flex-center position-ref full-height">
        @if (Route::has('login'))
        <div class="top-right links">
            @auth
            <a href="{{ url('/home') }}">Home</a>
            @else
            <a href="{{ route('login') }}">Login</a>

            @if (Route::has('register'))
            <a href="{{ route('register') }}">Register</a>
            @endif
            @endauth
        </div>
        @endif

        <div class="content">
            <div class="title m-b-md">
                Laravel Autopopulate dropdown
            </div>

            <div style="padding:5rem;">
                <div class="row">
                    <div class="col-6">
                        <div class="form-group">
                            <select name="country" id="country" class="form-control">
                                <option value="">-- select country --</option>
                                @foreach ($countries as $country)
                                <option value="{{$country->id}}">{{$country->name}}</option>
                                @endforeach
                            </select>
                        </div>
                    </div>
                    <div class="col-6">
                        <div class="form-group">
                            <select name="" id="state" class="form-control" disabled>
                                <option value="">-- select state --</option>
                            </select>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>



    <script>
        $(document).ready(function() {
            $.ajaxSetup({
                headers: {
                    'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
                }
            });

            $("#country").change(function() {
                console.log($(this).val());
                $.ajax({
                    url: "/state/" + $(this).val(),
                    method: 'GET',
                    success: function(data) {
                        $('#state').prop('disabled', false);
                        $('#state').html(data.html);
                    }
                });
            });
        });
    </script>
</body>

</html>

To test, run

php artisan serve

and open the url below in your browser

http://localhost:8000

I hope this helped.