Adding AJAX pagination to your list views

We will need to list all bookmarked images on our website. We will use AJAX pagination to build infinite scroll functionality. Infinite scroll is achieved by loading the next results automatically when the user scrolls to the bottom of the page.

We will implement an image list view that will handle both standard browser requests and AJAX requests, including pagination. When the user initially loads the image list page, we will display the first page of images. When they scroll to the bottom of the page, we load the following page of items via AJAX and append it to the bottom of the main page.

The same view will handle both standard and AJAX pagination. Edit the views.py file of the images application and add the following code to it:

from django.http import HttpResponse
from django.core.paginator import Paginator, EmptyPage,
PageNotAnInteger

@login_required
def image_list(request):
images = Image.objects.all()
paginator = Paginator(images, 8)
page = request.GET.get('page')
try:
images = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer deliver the first page
images = paginator.page(1)
except EmptyPage:
if request.is_ajax():
# If the request is AJAX and the page is out of range
# return an empty page
return HttpResponse('')
# If page is out of range deliver last page of results
images = paginator.page(paginator.num_pages)
if request.is_ajax():
return render(request,
'images/image/list_ajax.html',
{'section': 'images', 'images': images})
return render(request,
'images/image/list.html',
{'section': 'images', 'images': images})

In this view, we create a QuerySet to return all images from the database. Then, we build a Paginator object to paginate the results, retrieving eight images per page. We get an EmptyPage exception if the requested page is out of range. If this is the case and the request is done via AJAX, we return an empty HttpResponse that will help us stop the AJAX pagination on the client side. We render the results to two different templates:

  • For AJAX requests, we render the list_ajax.html template. This template will only contain the images of the requested page.
  • For standard requests, we render the list.html template. This template will extend the base.html template to display the whole page and will include the list_ajax.html template to include the list of images.

Edit the urls.py file of the images application and add the following URL pattern to it:

path('', views.image_list, name='list'),

Finally, we will need to create the templates mentioned here. Inside the images/image/ template directory, create a new template and name it list_ajax.html. Add the following code to it:

{% load thumbnail %}

{% for image in images %}
<div class="image">
<a href="{{ image.get_absolute_url }}">
{% thumbnail image.image "300x300" crop="100%" as im %}
<a href="{{ image.get_absolute_url }}">
<img src="{{ im.url }}">
</a>
{% endthumbnail %}
</a>
<div class="info">
<a href="{{ image.get_absolute_url }}" class="title">
{{ image.title }}
</a>
</div>
</div>
{% endfor %}

The preceding template displays the list of images. We will use it to return results for AJAX requests. Create another template in the same directory and name it list.html. Add the following code to it:

{% extends "base.html" %}

{% block title %}Images bookmarked{% endblock %}

{% block content %}
<h1>Images bookmarked</h1>
<div id="image-list">
{% include "images/image/list_ajax.html" %}
</div>
{% endblock %}

The list template extends the base.html template. To avoid repeating code, we included the list_ajax.html template for displaying images. The list.html template will hold the JavaScript code for loading additional pages when scrolling to the bottom of the page.

Add the following code to the list.html template:

{% block domready %}
var page = 1;
var empty_page = false;
var block_request = false;

$(window).scroll(function() {
var margin = $(document).height() - $(window).height() - 200;
if ($(window).scrollTop() > margin && empty_page == false &&
block_request == false) {
block_request = true;
page += 1;
$.get('?page=' + page, function(data) {
if(data == '') {
empty_page = true;
}
else {
block_request = false;
$('#image-list').append(data);
}
});
}
});
{% endblock %}

The preceding code provides the infinite scroll functionality. We include the JavaScript code in the domready block that we defined in the base.html template. The code is as follows:

  1. We define the following variables:
    • page: Stores the current page number.
    • empty_page: Allows us to know whether the user is on the last page and retrieves an empty page. As soon as we get an empty page, we will stop sending additional AJAX requests because we will assume that there are no more results.
    • block_request: Prevents us from sending additional requests while an AJAX request is in progress.
  2. We use $(window).scroll() to capture the scroll event and also to define
    a handler function for it.
  3. We calculate the margin variable to get the difference between the total document height and the window height, because that's the height of the remaining content for the user to scroll. We subtract a value of 200 from the result so that we load the next page when the user is closer than 200 pixels to the bottom of the page.
  4. We only send an AJAX request if no other AJAX request is being done (block_request has to be false) and the user didn't get to the last page of results (empty_page is also false).
  5. We set block_request to true to avoid a situation whereby the scroll event triggers additional AJAX requests, and increase the page counter by one,
    in order to retrieve the next page.
  6. We perform an AJAX GET request using $.get() and receive the HTML response in a variable called data. The following are the two scenarios:
    • The response has no content: We got to the end of the results, and there are no more pages to load. We set empty_page to true to prevent additional AJAX requests.
    • The response contains data: We append the data to the HTML element with the image-list ID. The page content expands vertically appending results when the user approaches the bottom of the page.

Open http://127.0.0.1:8000/images/ in your browser. You will see the list of images you have bookmarked so far. It should look similar to this:

Scroll to the bottom of the page to load additional pages. Ensure that you have bookmarked more than eight images using the bookmarklet because that's the number of images we are displaying per page. Remember that you can use Firebug or a similar tool to track the AJAX requests and debug your JavaScript code.

Finally, edit the base.html template of the account application and add the URL for the images item of the main menu, as follows:

<li {% if section == "images" %}class="selected"{% endif %}>
<a href="{% url "images:list" %}">Images</a>
</li>

Now you can access the image list from the main menu.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.152.157