Flask and Bootstrap 5 - Creating a macro for pagination
The Bootstrap pagination component looks like this:
<nav>
<ul class="pagination">
<li class="page-item"><a class="page-link" href="#">Previous</a></li>
<li class="page-item"><a class="page-link" href="#">1</a></li>
<li class="page-item"><a class="page-link" href="#">2</a></li>
<li class="page-item"><a class="page-link" href="#">3</a></li>
<li class="page-item"><a class="page-link" href="#">Next</a></li>
</ul>
</nav>
It has 3 main blocks, the previous page, the numbering and the next page; with this clear, let's create a macro in Jinja that we can easily reuse in any other module:
my_app\templates\macro\pagination.html
{% macro m_pagination(pagination, url='tasks.index') %}
<nav>
<ul class="pagination justify-content-center">
{% if pagination.has_prev %}
<li class="page-item">
<a class="page-link" href="{{ url_for(url,page=pagination.prev_num) }}" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
{% endif %}
{% for page in pagination.iter_pages() %}
{% if page != pagination.page %}
<li class="page-item">
<a class="page-link" href="{{ url_for(url,page=page) }}" aria-label="Previous">
<span aria-hidden="true">{{ page }}</span>
</a>
</li>
{% else %}
<li class="page-item active">
<a class="page-link" href="#" aria-label="Previous">
<span aria-hidden="true">{{ page }}</span>
</a>
</li>
{% endif %}
{% endfor %}
{% if pagination.has_next %}
<li class="page-item">
<a class="page-link" href="{{ url_for(url,page=pagination.next_num) }}" aria-label="Previous">
<span aria-hidden="true">»</span>
</a>
</li>
{% endif %}
</ul>
</nav>
{% endmacro %}
Remember that macros are a type of functions that we have available in Jinja and through them we can supply parameters, which would be the data variable, in this example, the pagination object and a URL; as a consideration, we branched using a conditional to mark the active page and suspend navigation to itself:
{% if page != pagination.page %}
<li class="page-item">
<a class="page-link" href="{{ url_for(url,page=page) }}" aria-label="Previous">
<span aria-hidden="true">{{ page }}</span>
</a>
</li>
{% else %}
<li class="page-item active">
<a class="page-link" href="#" aria-label="Previous">
<span aria-hidden="true">{{ page }}</span>
</a>
</li>
{% endif %}
To use it, for example, from the task list:
my_app\tasks\controllers.py
def index():
return render_template('dashboard/task/index.html', tasks=operations.pagination(request.args.get('page', 1, type=int)))
As you can see, we are receiving an argument for the URL; that is, of type GET called page:
request.args.get('page')
We indicate a default value, to avoid comparing with null values:
request.args.get('page', 1)
And the type, which by default is String:
request.args.get('page', 1, type=int)
And from the template:
my_app\templates\dashboard\task\index.html
{% extends "dashboard/master.html" %}
{% from 'macro/pagination.html' import m_pagination %}
***
{% block content %}
<table class="table">
<tr>
<td>Id</td>
<td>Name</td>
<td>Options</td>
</tr>
{% for t in tasks.items %}
***
</table>
{{ m_pagination(tasks) }}
{% endblock %}
And we will have:
- Andrés Cruz
Develop with Laravel, Django, Flask, CodeIgniter, HTML5, CSS3, MySQL, JavaScript, Vue, Android, iOS, Flutter