Динамичные select в форме (Laravel + jQuery)

Предположим у нас следующая задача: Необходимо сделать простую форму для выбора стран и городов. В форме имеются два поля выбора (select), в первом выбирается страна, а во втором города и в зависимости от выбранной страны города будут разные.
Мы будем работать в фреймворке Laravel. Предполагается, что у вас уже создана БД и в файле .env указаны необходимые настройки к ее подключению.
Создаем модели и миграции
Нам понадобятся две таблицы:
- Страны
- Города
Создаем две модели Country и City:
php artisan make:model Country -m
php artisan make:model City -m
Мы добавили флаг -m, чтобы одновременно создалась миграция.
Далее идем в папку миграций (database/migrations
) и правим в них функцию up().
Вот так выглядит функция up() в миграции create_countries_table:
public function up()
{
Schema::create('countries', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->timestamps();
});
}
Вот так выглядит функция up() в миграции create_cities_table:
public function up()
{
Schema::create('cities', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->unsignedInteger('id_country');
$table->timestamps();
});
}
Далее выполняем миграцию:
php artisan migrate
После создания таблиц Страны и Города, их необходимо заполнить тестовыми данными для дальнейшей работы.

Создаем контроллер
Далее создаем контроллер, назовем его CountryController, для этого выполним команду:
php artisan make:controller CountryController
Идем в контроллер (app/Http/Controllers/CountryController.php
) и создаем функцию index() с помощью нее мы будем выводить нашу форму с динамическими полями select.
А так же функцию selectCity() с помощью которой мы будем обрабатывать ajax запросы из формы и возвращать список городов для определенной страны.
В конечном счете контроллер должен выглядеть так:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Country;
use App\City;
class CountryController extends Controller
{
public function index()
{
$countries = Country::all();
return view('country_form', ['countries' => $countries]);
}
public function selectCity(Request $request){
if($request->ajax()){
$cities = City::where('id_country',$request->id_country)->get()->pluck("name","id");
$data = view('selectcity',['cities' => $cities])->render();
return response()->json(['options'=>$data]);
}
}
}
Создание шаблонов
Пора создать шаблоны. Первый шаблон resources/views/country_form.blade.php
очень простой, сделаем его на основе стартового шаблона Bootstrap 4 (https://getbootstrap.com/docs/4.5/getting-started/introduction/#starter-template), в нем содержится только форма с двумя select полями.
<!doctype html>
<html lang="ru">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<title>Динамический select в Laravel</title>
</head>
<body>
<div class="container">
<h1>Динамический select в Laravel</h1>
<form>
@csrf
<div class="form-group">
<label for="countries">Страна</label>
<select class="form-control" id="countries">
<option>Выберите страну</option>
@foreach($countries as $country)
<option value="{{ $country->id }}">{{ $country->name }}</option>
@endforeach
</select>
</div>
<div class="form-group">
<label for="city">Город</label>
<select class="form-control" id="city">
<option>Выберите город</option>
</select>
</div>
</form>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.js"></script>
<script type="text/javascript">
$("#countries").change(function(){
var id_country = $(this).val();
var token = $("input[name='_token']").val();
console.log(id_country);
$.ajax({
url: "{{ route('selectcity') }}",
method: 'POST',
data: {id_country:id_country, _token:token},
success: function(data) {
$("#city").html('');
$("#city").html(data.options);
}
});
});
</script>
</body>
</html>
Создадим следующий шаблон resources/views/selectcity.blade.php
, который будет формировать список options для selecta выбора города и будет подгружаться в форму основного шаблона шаблон country_form.blade.php
<option>Выберите город</option>
@if(!empty($cities))
@foreach($cities as $key => $value)
<option value="{{ $key }}">{{ $value }}</option>
@endforeach
@endif
Завершающий этап
Не забудем добавить роуты, идем в routes/web.php
и дописываем:
Route::get('countryform', 'CountryController@index');
Route::post('selectcity', 'CountryController@selectCity')->name('selectcity');
Теперь все должно работать, идем по адресу нашей формы, в моем случае http://laratest.loc/countryform и проверяем:

Отлично, работает!