Laravel 11 Dynamic Dependent Dropdown Example

Laravel 11 Dynamic Dependent Dropdown Example tutorial, show you how to build dynamic dependent dropdown in Laravel 11 application using ajax jquery.

# Install Laravel App

This step is optional; however, if you haven’t yet created your Laravel application, you can proceed by running the following command:

composer create-project laravel/laravel laravel-app

# Create Models and Migrations

In this step we will generate Country, State and City model and migrations files. Let open your terminal and run all below 3 commands.

php artisan make:model Country -m 
php artisan make:model State -m 
php artisan make:model City -m 

First open the app/Models/Country.php and update the fillable properties.

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Country extends Model
{
use HasFactory;

/**
* Write code on Method
*
* @return response()
*/
protected $fillable = [
'name'
];
}

Next, open app/Models/State.php and update accordingly.

<?php
  
namespace App\Models;
  
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
  
class State extends Model
{
    use HasFactory;
  
    /**
     * Write code on Method
     *
     * @return response()
     */
    protected $fillable = [
        'name', 'country_id'
    ];
}

And open the last model app/Models/City.php and update the below code on it.

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class City extends Model
{
use HasFactory;

/**
* Write code on Method
*
* @return response()
*/
protected $fillable = [
'name', 'state_id'
];
}

Now, you will need to update the column names in the migration files. So first open database/migrations/create_countries_tables.php and update the columns inside the migrations.

<?php

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

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

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

Next open the database/migrations/create_states_tables.php and update the required column.

<?php

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

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

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

And last open database/migrations/create_cities_tables.php and update the column accordingly.

<?php

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

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

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

Then run created new migration with below command, it will generate the tables in your database.

php artisan migrate

# Create Routes

Next, you have to open the routes/web.php file; here you have to define the route.

<?php

use Illuminate\Support\Facades\Route;

use App\Http\Controllers\DependentController;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('dropdown', [DependentController::class, 'index']);
Route::post('api/states', [DependentController::class, 'states']);
Route::post('api/cities', [DependentController::class, 'cities']);

# Create Controller

You can quickly generate the controller using the composer command.

php artisan make:controller DependentController

app/Http/Controllers/DependentController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Country;
use App\Models\State;
use App\Models\City;

class DependentController extends Controller
{
/**
* Write code on Method
*
* @return response()
*/
public function index()
{
$data['countries'] = Country::get(["name", "id"]);
return view('dependent', $data);
}
/**
* Write code on Method
*
* @return response()
*/
public function states(Request $request)
{
$data['states'] = State::where("country_id", $request->country_id)
->get(["name", "id"]);

return response()->json($data);
}
/**
* Write code on Method
*
* @return response()
*/
public function cities(Request $request)
{
$data['cities'] = City::where("state_id", $request->state_id)
->get(["name", "id"]);

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

# Create View File

resources/views/dependent.blade.php

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
    <meta charset="utf-8">
    <meta name="csrf-token" content="content">
    <meta name="csrf-token" content="{{ csrf_token() }}">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- CSS only -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container mt-4" >
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="alert alert-primary mb-4 text-center">
                </div> 
                <form>
                    <div class="form-group mb-3">
                        <select  id="country-dependent" class="form-control">
                            <option value="">-- Select Country --</option>
                            @foreach ($countries as $data)
                            <option value="{{$data->id}}">
                                {{$data->name}}
                            </option>
                            @endforeach
                        </select>
                    </div>
                    <div class="form-group mb-3">
                        <select id="state-dependent" class="form-control">
                        </select>
                    </div>
                    <div class="form-group">
                        <select id="city-dependent" class="form-control">
                        </select>
                    </div>
                </form>
            </div>
        </div>
    </div>
  
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script>
        $(document).ready(function () {
  
            /*------------------------------------------
            Country dependent Change Event
            --------------------------------------------*/
            $('#country-dependent').on('change', function () {
                var idCountry = this.value;
                $("#state-dependent").html('');
                $.ajax({
                    url: "{{url('api/fetch-states')}}",
                    type: "POST",
                    data: {
                        country_id: idCountry,
                        _token: '{{csrf_token()}}'
                    },
                    dataType: 'json',
                    success: function (result) {
                        $('#state-dependent').html('<option value="">-- Select State --</option>');
                        $.each(result.states, function (key, value) {
                            $("#state-dependent").append('<option value="' + value
                                .id + '">' + value.name + '</option>');
                        });
                        $('#city-dependent').html('<option value="">-- Select City --</option>');
                    }
                });
            });
  
            /*------------------------------------------
            State dependentChange Event
            --------------------------------------------*/
            $('#state-dependent').on('change', function () {
                var idState = this.value;
                $("#city-dependent").html('');
                $.ajax({
                    url: "{{url('api/fetch-cities')}}",
                    type: "POST",
                    data: {
                        state_id: idState,
                        _token: '{{csrf_token()}}'
                    },
                    dataType: 'json',
                    success: function (res) {
                        $('#city-dependent').html('<option value="">-- Select City --</option>');
                        $.each(res.cities, function (key, value) {
                            $("#city-dependent").append('<option value="' + value
                                .id + '">' + value.name + '</option>');
                        });
                    }
                });
            });
  
        });
    </script>
</body>
</html>

# Create Seeder

Now create a Seeder file using below command for dummy data.

php artisan make:seeder CountrySateCitySeeder

Now open the database/seeders/CountrySateCitySeeder.php and update the following code on it.

<?php

namespace Database\Seeders;

use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use App\Models\Country;
use App\Models\State;
use App\Models\City;

class CountrySateCitySeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
/*------------------------------------------
--------------------------------------------
US Country Data
--------------------------------------------
--------------------------------------------*/
$country = Country::create(['name' => 'United State']);

$state = State::create(['country_id' => $country->id, 'name' => 'Juneau']);

City::create(['state_id' => $state->id, 'name' => 'Selma']);
City::create(['state_id' => $state->id, 'name' => 'Sheffield']);

/*------------------------------------------
--------------------------------------------
India Country Data
--------------------------------------------
--------------------------------------------*/
$country = Country::create(['name' => 'India']);

$state = State::create(['country_id' => $country->id, 'name' => 'Uttrakhand']);

City::create(['state_id' => $state->id, 'name' => 'Almora']);
City::create(['state_id' => $state->id, 'name' => 'Chamoli']);

}
}

Next, run seeder with below command:

php artisan db:seed --class=CountrySateCitySeeder

Run Laravel App:

All the required steps have been done, now you have to type the given below command and hit enter to run the Laravel app:

php artisan serve

Now, Go to your web browser, type the given URL and view the app output:

http://localhost:8000/dependent