((Making Ajax Request with jQuery and Laravel Part 2))
Hello again. continuing from our previous post on Ajax request with Laravel, this part of the article is written to help you get acquainted with asynchronous requests with Laravel and PHP. In this post, several of Laravel's features will be touched. So, let's dive in,Requirements:
To be able to implement this guide, you probably should make sure you have all these;
- Apache PHP
- MySQL or SQLite 3
- Laravel 5
- IDE, preferably Jetbrain's PHP storm.
In order to fully appreciate the ease of Ajax requests and the neatness of it within the Laravel framework and Blade engine, we are going to update the value of a select box, using the value of another select box, the likes of the dynamism you see when registraing a form that requires you to select a country, which in turns loads in the background, the locations in that country.
Step 1: Create Our Sample Tables/Migrations and Controllers:
NB: you can totally create this files manually without command prompt, the advantage to using CMD is, regardless of the Laravel version you're using, you are bound to get all the folder locations right if you use Artisan.
so, we first head over to artisan and create our migrations; Please note: to continue from here, it is best you already configured you system Path variable to also point to your PHP binaries folder.
open up Command Prompt (CMD) by searching and clicking on it in Start, or Window + R, then type CMD and run, which you navigate to the directory of your Laravel project:
Now using Artisan, create a sample migrations for the country and state tables, uisng the scripts below from your command prompt / terminal.
php artisan make:migration create_country_table --create="countries"
php artisan make:migration create_states_table --create="states"
php artisan make:model Country
php artisan make:model State
if you did above correctly, your CMD should look similar to the image below:
Now, we have our table and controllers all setup, we need to modify the migrations before we call migrate. let's headover to the migration files (database\migrations\).
STEP 2: Setup the Migration tables and Eloquent Relationships between both Tables
This is the step where we define the columns we want in our tables; go into your create_countries_table.php, found in database\migrations\ and edit the php to suit your taste, sample with just country name is outlined below;
database\migrations\xxxx_xx_xx_xxxxxx_create_countries_table.php
class CreateCountriesTable extends Migration
{
public function up()
{
Schema::create('countries', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
}
public function down()
{
Schema::drop('countries');
}
}
as can be seen, above, we modified the default code Artisan placed in our countries table by adding a name column of type string, this creates a varchar column with the same name in you database. The incremental column 'id' , is an auto-increment integer column, and the timestamps as you are aware already represents the created_at, and published_at timestamp columns.
class CreateCountriesTable extends Migration
{
public function up()
{
Schema::create('countries', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
}
public function down()
{
Schema::drop('countries');
}
}
as can be seen, above, we modified the default code Artisan placed in our countries table by adding a name column of type string, this creates a varchar column with the same name in you database. The incremental column 'id' , is an auto-increment integer column, and the timestamps as you are aware already represents the created_at, and published_at timestamp columns.
Now, we go over to the create_states_migration and modify the code to fit our context of states, belonging to a country.
database\migrations\xxxx_xx_xx_xxxxxx_create_states_table.php
As depicted in the php above, we have been able to specify the foreign key 'country_id', to hep link the states, to the country they belongs to.
class CreateStatesTable extends Migration
{
public function up()
{
Schema::create('states', function (Blueprint $table) {
$table->increments('id');
$table->integer('country_id')->unsigned();
$table->string('name');
$table->timestamps();
$table->foreign('country_id')
->references('id')
->on('countries')
->onDelete('cascade');
});
}
public function down()
{
Schema::drop('states');
}
}
{
public function up()
{
Schema::create('states', function (Blueprint $table) {
$table->increments('id');
$table->integer('country_id')->unsigned();
$table->string('name');
$table->timestamps();
$table->foreign('country_id')
->references('id')
->on('countries')
->onDelete('cascade');
});
}
public function down()
{
Schema::drop('states');
}
}
As depicted in the php above, we have been able to specify the foreign key 'country_id', to hep link the states, to the country they belongs to.
Now we, head over to their models and setup methods to assist Eloquent in understanding the relationship between the two entities. So we open up our models and update them as depicted below;
app\Country.php
class Country extends Model
{
public function states(){
return $this->hasMany('App\State');
}
}
{
public function states(){
return $this->hasMany('App\State');
}
}
The hasMany method of Eloquent, as used in the states() method, is used to show relationship between models in the system, the one above has shown that, >= 1 states in the states table can belong to a Country object :D . Hence, easing querying for all states under a country.
app\State.php
class State extends Model
{
public function country()
{
return $this->belongsTo('App\Country');
}
}
{
public function country()
{
return $this->belongsTo('App\Country');
}
}
as you can see, we have also specified here in the country method of the State model, an eloquent relation method, that helps teh system understand each state belongs to one and only one country, hence the approach reduces manual quering by a big plus.
Step 3: Now we Migrate
Head back over to your command prompt, if you've closed command prompt, you must navigate back to your project folder to run PHP Artisan commands.
Type into the command prompt / CMD the artisan task below;
PHP artisan migrate.
This will create all the tables as specified in the migration files and that is that. We are almost done.
Optional Step
let's populate the tables with sample data to practice with (from terminal or command prompt);
php artisan tinker
$country = new App\Country
$country->name = 'USA'
$country->save();
to view all the $country in the system, so you can know which id to assign to which for the next operation, enter;
app\Country::all()->toArray()
Now that you've gotten the your IDs, let register some states shall we!!! :D
$state = new App\State
$state->name = 'New York'
$state->country_id = 1
$state->save()
You can give your eloquent relationship methods a test by checking for all the states belonging to a country by entering:
$country = App\Country::first()
$country->states->toArray()
and it's output should be similar to the below:
>>> $country = App\Country::first()
=> <App\Country #000000006b119b49000000005f5c2cd6> {
id: 1,
name: "Nigeria",
created_at: "2015-07-22 17:06:03",
updated_at: "2015-07-22 17:06:03"
}
>>> $country->states->toArray()
=> [
[
"id" => 1,
"country_id" => 1,
"name" => "Lagos",
"created_at" => "2015-07-22 17:06:55",
"updated_at" => "2015-07-22 17:06:55"
],
[
"id" => 2,
"country_id" => 1,
"name" => "Abuja",
"created_at" => "2015-07-22 17:08:04",
"updated_at" => "2015-07-22 17:08:04"
]
]
>>>
Step 4: Apply our Ajax Knowledge From Here, to Implement a Dynamic Select Box
create a sample blade file, and fill it with html, with two select boxes. Let's call our blade file, test.blade.php.
and build our routes file to open teh test view, when we visit /test. Therefore, you will need to update your Routes file with the line shown below
app\Http\routes.php
Route::get('test',function(){
$countries = Country::all();
return view('test')->with(['countries'=>$countries]);
});
$countries = Country::all();
return view('test')->with(['countries'=>$countries]);
});
Now you can see, we passed all the countries in our database to the blade file, and looped through the collection with @foreach
resources\views\test.blade.php
<!doctype html>
<html>
<head>
<title>Test Laravel Ajax</title>
<script src="http://code.jquery.com/jquery-1.8.2.min.js" type="text/javascript"></script>
</head>
<body>
<select id="countries" name="countries" style="width: 300px">
<option value="-1">Please select a Country</option>
@foreach($countries as $country)
<option value="{{$country->id}}">{{$country->name}}</option>
@endforeach
</select>
<br/>
<br/>
<select id="state" name="state" style="width: 300px">
</select>
</body>
</html>
<html>
<head>
<title>Test Laravel Ajax</title>
<script src="http://code.jquery.com/jquery-1.8.2.min.js" type="text/javascript"></script>
</head>
<body>
<select id="countries" name="countries" style="width: 300px">
<option value="-1">Please select a Country</option>
@foreach($countries as $country)
<option value="{{$country->id}}">{{$country->name}}</option>
@endforeach
</select>
<br/>
<br/>
<select id="state" name="state" style="width: 300px">
</select>
</body>
</html>
sample output below;
up next, we'll add the ajax request route, since we're expecting the id of the selected country, we can just make a simple update to our routes by adding this; *****
Route::get('test',function(){
$countries = Country::all(); return view('test')->with(['countries'=>$countries]);
});
Route::get('ajax/states/{id}', function($id){
$country = Country::find($id); return $country->states->toArray();
});
up next, we'll add the ajax request route, since we're expecting the id of the selected country, we can just make a simple update to our routes by adding this; *****
Route::get('test',function(){
$countries = Country::all(); return view('test')->with(['countries'=>$countries]);
});
Route::get('ajax/states/{id}', function($id){
$country = Country::find($id); return $country->states->toArray();
});
and then we'll add a bit of Javascript/jQuery to our test view to enable the request and updating.
test.blade.php *****
<script type="text/javascript">
$(function(){
$('#countries').change(function(){
$("#state").html("");
$.ajax({
url: "ajax/states/1",
dataType: "json",
async:true,
success: function(reply){
var markup = "";
for(var i=0; i<reply.length; i++)
{
markup+="<option value='"+ reply[i].id +"'>"+reply[i].name+"</option>"; }
$("#state").html(markup);
},
error: function(reply){
alert("in error "+reply);
},
complete: function(reply){
}
})
});
});
</script>
And that's about it. Have fun! :D
test.blade.php *****
<script type="text/javascript">
$(function(){
$('#countries').change(function(){
$("#state").html("");
$.ajax({
url: "ajax/states/1",
dataType: "json",
async:true,
success: function(reply){
var markup = "";
for(var i=0; i<reply.length; i++)
{
markup+="<option value='"+ reply[i].id +"'>"+reply[i].name+"</option>"; }
$("#state").html(markup);
},
error: function(reply){
alert("in error "+reply);
},
complete: function(reply){
}
})
});
});
</script>
And that's about it. Have fun! :D