Monday 20 February 2017

How to Create Ajax Pagination Using Laravel

In this article I will demonstrate one way to create an Ajax pagionation using Laravel and jQuery. In order to understand this post, you need to be familiar with standard (non-Ajax) Laravel’s paginator (how it works), and you should also have a basic knowledge of Ajax and jQuery.

Let’s say that we have a simple Laravel webiste with articles and we want to have Ajax pagination on the page that shows (lists) all of the articles (for example, this page can be accessed fromwww.example.com/articlesand it displays paginated lists of article titles where each of these titles is a link):

First, let’s define a partial view inresources/views/articles/load.blade.phpfor displaying pagination results:
<div id="load" style="position: relative;">
@foreach($articles as $article)
    <div>
        <h3>
            <a href="{{ action('ArticleController@show', [$article->id]) }}">{{$article->title }}</a>
        </h3>
    </div>
@endforeach
</div>
{{ $articles->links() }}
Note that there is{{ $articles->links() }}at the bottom – the Laravel’s links method will render the links to the rest of the pages in the result set. Each of these links will already contain the proper page query string variable. As for the<div id="load" style="position: relative;">– you’ll see its purpose later.
This partial view will be rendered and returned as a response to a jQuery Ajax Request. Let’s get this straight: when the user clicks on the pagination link (number) – an Ajax request containing URI with the proper page query string variable (page number) will be sent to theindexmethod that is defined inArticleController. So, let’s see how thatindexmethod looks like:
class ArticleController extends Controller
{
    protected $articles;

    public function __construct(Article $articles)
    {
        $this->articles = $articles;
    }


    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index(Request $request)
    {
        $articles = $this->articles->latest('created_at')->paginate(5);

        if ($request->ajax()) {
            return view('articles.load', ['articles' => $articles])->render();  
        }

        return view('articles.index', compact('articles'));
    }
As you can see,  in theindexmethod we first use thepaginatemethod on an Eloquent query:
$articles = $this->articles->latest('created_at')->paginate(5);
Thepaginatemethod provided by Laravel automatically takes care of setting the proper limit and offset based on the current page being viewed by the user. By default, the current page is detected by the value of the?pagequery string argument on the HTTP request. Of course, this value is automatically detected by Laravel, and is also automatically inserted into links generated by the paginator1. Those paginated results are stored in the$articlesvariable.
Next, we check if the received request is actually an Ajax request:
        if ($request->ajax()) {
            return view('articles.load', ['articles' => $articles])->render();  
        }
If it is, we will pass the$articlesvariable to the partial view defined inresources/views/articles/load.blade.php, render it and return as HTML response.
Finally, we want  to make sure that our website is working if JavaScript is disabled; in that case we’ll have a standard (non-Ajax) pagination:
return view('articles.index', compact('articles'));
As you can see, we pass$articlesinto the viewresources/views/articles/index.blade.phpand return it.
Now, let’s define that view located inresources/views/articles/index.blade.php:
<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta charset="UTF-8">
    <title>Larave Ajax Pagination</title>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container">
        <div class="row">
            
            <div class="col-sm-9">
                @if (count($articles) > 0)
                    <section class="articles">
                        @include('articles.load')
                    </section>
                @endif
            </div>

            <div class="col-sm-3">
            </div>
        </div>
    </div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
</body>
</html>
Note that we are including partial viewresources/views/articles/load.blade.phpthat we defined earlier. Now, if we register a resourceful route inapp/Http/routes.php(or if you are using Laravel 5.3 inroutes/web.php):
Route::resource('articles', 'ArticleController');
we will have a standard (non-Ajax) pagination that is working (you can test it).
The next step is to put the following jQuery just above</body>:
<script type="text/javascript">

$(function() {
    $('body').on('click', '.pagination a', function(e) {
        e.preventDefault();

        $('#load a').css('color', '#dfecf6');
        $('#load').append('<img style="position: absolute; left: 0; top: 0; z-index: 100000;" src="/images/loading.gif" />');

        var url = $(this).attr('href');  
        getArticles(url);
        window.history.pushState("", "", url);
    });

    function getArticles(url) {
        $.ajax({
            url : url  
        }).done(function (data) {
            $('.articles').html(data);  
        }).fail(function () {
            alert('Articles could not be loaded.');
        });
    }
});

</script>
Let’s analyze this script:
$('body').on('click''.pagination a'function(e) {– here we attach an event handler function to the “click” event (to the click on the pagination link). And, when a user clicks on the pagination link – the default action of the event will not be triggered [e.preventDefault();].
Next, we temporarily change the color of the listed titles of articles (which are links) and we append loading.gif image (with an absolute position) inside of<div id="load"style="position: relative;">(which is inresources/views/articles/load.blade.phpthat we defined earlier).
var url = $(this).attr('href');– this will get the value of the href attribute of the pagination link that was clicked. For example, if the user clicked on the number 2 link – the value of theurlvariable would behttp://example.com/articles?page=2.
Finally, we are passing this URL to thegetArticlesfunction which just sends an HTTP (Ajax) request to that URL. And since we defined a resourceful route inapp/Http/routes.php(or if you are using Laravel 5.3 inroutes/web.php) – we are actually sending Ajax request to theindexmethod defined inArticleController. If everything is ok (if theindexmethod returned rendered HTML response) – we just need to set the HTML contents:$('.articles').html(data);If something went wrong – you can do whatever you want, in my case an alert box pops up with the message “Articles could not be loaded”.
Lastly, there iswindow.history.pushState("""", url);to keep (show) pagination URLs in the address bar so that the users can bookmark or share the links…
So, here is the final version ofresources/views/articles/index.blade.php:
<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta charset="UTF-8">
    <title>Laravel Ajax Pagination</title>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container">
        <div class="row">
            <div class="col-sm-9">

                @if (count($articles) > 0)
                    <section class="articles">
                        @include('articles.load')
                    </section>
                @endif

            </div>

            <div class="col-sm-3">
            </div>
        </div>
    </div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>

    <script type="text/javascript">

        $(function() {
            $('body').on('click', '.pagination a', function(e) {
                e.preventDefault();

                $('#load a').css('color', '#dfecf6');
                $('#load').append('<img style="position: absolute; left: 0; top: 0; z-index: 100000;" src="/images/loading.gif" />');

                var url = $(this).attr('href');
                getArticles(url);
                window.history.pushState("", "", url);
            });

            function getArticles(url) {
                $.ajax({
                    url : url
                }).done(function (data) {
                    $('.articles').html(data);
                }).fail(function () {
                    alert('Articles could not be loaded.');
                });
            }
        });
    </script>
</body>
</html>
And that’s it. If you know a better or a more elegant way to implement this, please let me know.
This Tutorial Taken from Laraget.Com . Thanks

0 comments: