Code Happy: AJAX Content

← Back to Index

Please note that this chapter was written for VERSION 3 of the Laravel PHP Framework.

Modern web applications don't have the time to be waiting around for the next HTTP request. Javascript has changed the way we browse, we want our content to automatically update. We want to post information without having to reload the page.

In the Laravel IRC channel we often get asked how to use Ajax alongside Laravel, which seems confusing, because the answer is simply 'like any other HTTP request'. Let's dive right in and look at some Ajax requests using the framework. We are going to need to make some HTTP requests through Javascript, this can get ugly so I have decided to use the jQuery Javascript framework in these examples.

Page Template

We will need a view, or page template to serve with our first request, so let's put together something basic.

<!-- application/views/template.php -->
<!DOCTYPE HTML>
<html>
<head>
    <meta charset="UTF-8">
    <title>My Ajax Page</title>
</head>
<body>
    <div id="content">
        <p>Hello and welcome to the site!</p>
    </div>
    <a href="#" id="load-content">Load Content</a>
</body>
</html>

There we go, now we have a content area, defined in a <DIV> element with the id of content, this is where we will load out future content. We also have a link with the id of load-content which we can use as a trigger to load our new content into the <DIV> above.

Before we can see this view, we will need to define a route to load it, I am going to make it my base route..

<?php

// application/routes.php
Route::get('/', function() {
    return View::make('template');
});

Now if we visit http://localhost we are greeted with our site template, but clicking on the load content link isn't going to do a lot without some Javascript. Although we wouldn't need Javascript if we didn't have something to load, let's create a new route and view for content that is to be loaded into the content <DIV>.

First the view..

<!-- application/views/content.php -->
<h1>New Content</h1>
<p>This is our AJAX loaded content.</p>

and a route to serve the content, note that we aren't embedding the content within a template, if we did that the template would be repeated twice when we AJAX load our new content.

<?php

// application/routes.php
Route::get('content', function() {
    return View::make('content');
});

Great so now we have our main template, and we have a secondary route with some content to load via AJAX, so let's get started with the Javascript.

The Javascript

Now I'm a PHP developer, so my Javascript skills aren't going to blow anyones minds in this chapter. If you can find a better way to perform these actions (and there are many alternatives) then go ahead and try them, I'm sure you can do better!

First let's create a new file called script.js and put it in public/js along with the latest version of jQuery which in my case is simply called jquery.js. Let's edit our main template to add references to these files using the HTML::script() method.

<!-- application/views/template.php -->
<!DOCTYPE HTML>
<html>
<head>
    <meta charset="UTF-8">
    <title>My Ajax Page</title>
</head>
<body>
    <div id="content">
        <p>Hello and welcome to the site!</p>
    </div>
    <a href="#" id="load-content">Load Content</a>

    <!-- javascript files -->
    <script type="text/javascript">var BASE = "<?php echo URL::base(); ?>";</script>
    <?php echo HTML::script('js/jquery.js'); ?>
    <?php echo HTML::script('js/script.js'); ?>
</body>
</html>

As you can see, I have referenced my Javascript files before the closing tag, so that the HTTP requests to load them don't block the page loading. This is a good practice to stick to. Let's get started and add some Javascript to our public/js/script.js file.

We also create a new BASE variable so that Javascript is aware of the base URL to our application, we will need this later to create request URLs.

// public/js/script.js
jQuery(document).ready(function($) {
    // perform javascript only when the document
    // has been fully loaded
});

Here we are using the jQuery() object to get a handle on the current document, and adding a ready() event with a closure to hold our code. By waiting for the document object to be ready() we can be sure that all DOM objects have loaded, and that the jQuery library has been loaded.

You may see other examples written like this..

// public/js/script.js
$(document).ready(function() {
    // perform javascript only when the document
    // has been fully loaded
});

This is fine, but could lead to problems if other Javascript libraries chose to use the $ object at a later date. My method uses the jQuery class, and hands the inner closure a $ which is reassigned to the jQuery object. This prevents any collisions.

Let's get started on creating a click event for our content loader link, there are many ways to do this with jQuery, I am going to use the .click() method. Here we go..

// public/js/script.js
$(document).ready(function() {

    $('#load-content').click(function(e) {
        e.preventDefault();
    })

});

Now we have a click event defined, with a callback closure. By providing an event parameter called e to the inner closure, we can use the e.preventDefault(); method to prevent the default click action from being performed. In this case the link will not act as a hyper-link. Now we need to make another HTTP request to GET the new content, and load it into our #content area. Let's use the jQuery .get() method to perform this task.

// public/js/script.js
$(document).ready(function() {
    $('#load-content').click(function(e) {
        // prevent the links default action
        // from firing
        e.preventDefault();

        // attempt to GET the new content
        $.get(BASE+'content', function(data) {
            $('#content').html(data);
        });
    })
});

Remember the BASE attribute we set earlier? We can use it to build our request URL, and create a callback method to catch the data that is returned. We will inject the response from our GET request into the #content element using the .html() method.

That was a lot of hard work wasn't it? Well at least now we can see our hard work in action, let's load up the application at http://localhost and click the load content link. Hopefully it worked!

So as you can see, using AJAX with Laravel is the same as using any other framework or plain PHP, just be sure you format the views for your AJAX routes in a suitable manner.

Post Data

Sometimes you need to send extra along with your requests, let's create a new POST HTTP request with jQuery to demonstrate how this can be done. First we will need a route that will respond to a POST request.

<?php

// application/routes.php
Route::post('content', function() {
    // deal with the post data..
});

By using the Route::post() method instead of get() our content route will now respond to our POST request, let's get started on the Javascript.

// attempt a POST request with
// some additional data
$.post(BASE+'content', {
    name: "Dayle",
    age: 27
}, function(data) {
    $('#content').html(data);
});

We are using the POST method to post some data to the content route, we can receive the data with Laravel in a similar manner to form processing using the Input class.

<?php

// application/routes.php
Route::post('content', function() {
    echo Input::get('name');    // Dayle
    echo Input::get('age');     // 27
});

Simple as that!

JSON Responses

When interacting with Javascript, its useful to be able to return data in JSON format, a string based array that Javascript is more familiar with.

To return a JSON response, first we need to encode our PHP array, and then send the appropriate headers to inform the client of our JSON content type.

The above quote used to be true, but the method Response::json() was added with Laravel 3.2 which achieves the same goal.

Let's create a new route.

<?php

// application/routes.php
Route::get('content', function() {

    // our data array, soon to be JSON
    $data = array(
        'name'      => 'Dummy',
        'size'      => 'XL',
        'color'     => 'Blue'
    );

    return Response::json($data);

});

Finally we return a response object, passing our data array to the json() method which is JSON encoded for us. We can optionally pass a different status code other than 200 as a second parameter.

Detecting an AJAX Request

Sometimes its useful to within the route whether a request has been made using AJAX. Fortunately Laravel provides a method to detect AJAX requests. Let's take a look.

<?php

// application/routes.php
Route::get('content', function() {

    // check to see if the request is
    // an AJAX one.
    if (Request::ajax())
    {
        // provide the ajax content
        return View::make('only_content');
    }

    // provide the full content
    return View::make('content_with_layout');

});

The Request::ajax() returns a boolean true if the request is an AJAX request, and boolean false if not.

My books are available online for free to encourage learning. However, if you'd like for me to keep writing, then please consider buying a digital copy over at Leanpub.com.

It's available in PDF, ePub, and Kindle format, and contains a bunch of extras that you won't find on the site. I have a full-time job, and I write my books in my spare time. Please consider buying a copy so that I can continue to write new books from the comfort of my sofa!