Pagination HTMX partial

The pagination links need to trigger HTMX requests and update the correct target.

First, modify your task_index.html to include a container for the table and pagination:

<div id="task-container">
    <table class="table">
        <thead>
            <tr>
                <th>Task</th>
                <th>Created On</th>
                <th>Notes</th>
                <th>Actions</th>
            </tr>
        </thead>
        <tbody id="taskList"
               hx-trigger="load"
               hx-get="{% url 'console_app:task_index' %}"
               hx-target="this">
        </tbody>
    </table>
</div>

Second, update your task_row.html to include HTMX attributes in the pagination links:

{% for task in page_obj %}
<tr>
    <td>{{ task.task }}</td>
    <td>{{ task.created_on }}</td> 
    <td>{{ task.notes }}</td> 
    <td>
        <button type="button" hx-get="{% url 'console_app:mark_task' task.pk %}" hx-target="#taskList">✔</button>
        <button type="button" hx-get="{% url 'console_app:delete_task' task.pk %}" hx-target="#taskList">DEL</button>
        <button type="button" hx-get="{% url 'console_app:edit_task' task.pk %}" hx-target="closest tr">Edit</button>
    </td>
</tr>
{% endfor %}

<tr>
    <td colspan="4">
        <div class="btn-group" role="group" aria-label="Item pagination">
            {% if page_obj.has_previous %}
                <button class="btn btn-outline-primary"
                        hx-get="{% url 'console_app:task_index' %}?page={{ page_obj.previous_page_number }}"
                        hx-target="#taskList">&laquo;</button>
            {% endif %}

            {% for page_number in page_obj.paginator.page_range %}
                {% if page_obj.number == page_number %}
                    <button class="btn btn-primary active">{{ page_number }}</button>
                {% else %}
                    <button class="btn btn-outline-primary"
                            hx-get="{% url 'console_app:task_index' %}?page={{ page_number }}"
                            hx-target="#taskList">{{ page_number }}</button>
                {% endif %}
            {% endfor %}

            {% if page_obj.has_next %}
                <button class="btn btn-outline-primary"
                        hx-get="{% url 'console_app:task_index' %}?page={{ page_obj.next_page_number }}"
                        hx-target="#taskList">&raquo;</button>
            {% endif %}
        </div>
        <div>Total record count: {{ count }}</div>
    </td>
</tr>

Third, update your view to handle both initial and HTMX requests:

def task_index(request):
    tasks = Task.objects.all().order_by(_TASK_ORDBY)   
    paginator = Paginator(tasks, 4)  
    page_number = request.GET.get('page', 1)  
    
    try:
        page_obj = paginator.page(page_number) 
    except PageNotAnInteger:
        page_obj = paginator.page(1) 
    except EmptyPage:
        page_obj = paginator.page(paginator.num_pages)

    context = {
        'page_obj': page_obj,
        'count': tasks.count()
    }

    if request.htmx:
        template = 'console_app/task_row.html'
    else:
        template = 'console_app/task_index.html'
    
    return render(request, template, context)

Fourth, I suppose that your urls.py contain something like this:

urlpatterns = [
    path('console/', console_view, name='console_view'),
    path('tasks/', task_index, name='task_index'),

]
1 Like