Awesome post, thank you! A perfect integration of htmx, django-filter and django-tables.
With some minor changes also infinite scroll is possible:
Add a template rendering the table rows with the last row triggering the loading of more rows (google htmx infinite-scroll. I cant post links here???) . Add url parameter lazy=1 in hx-get to flag infinite scroll request:
{# templates/bootstrap_htmx_rows.html #}
{% load django_tables2 %}
{% load i18n %}
{% for row in table.paginated_rows %}
{% with lastrow=forloop.last %}
{% block table.tbody.row %}
<tr {{ row.attrs.as_html }} {% if lastrow and table.page.has_next %}hx-get="{% querystring table.prefixed_page_field=table.page.next_page_number "lazy"="1" %}" hx-trigger="revealed" hx-swap="afterend"{% endif %}>
{% for column, cell in row.items %}
<td {{ column.attrs.td.as_html }}>{% if column.localize == None %}{{ cell }}{% else %}{% if column.localize %}{{ cell|localize }}{% else %}{{ cell|unlocalize }}{% endif %}{% endif %}</td>
{% endfor %}
</tr>
{% endblock table.tbody.row %}
{% endwith %}
{% empty %}
{% if table.empty_text %}
{% block table.tbody.empty_text %}
<tr><td colspan="{{ table.columns|length }}">{{ table.empty_text }}</td></tr>
{% endblock table.tbody.empty_text %}
{% endif %}
{% endfor %}
Override the table.tbody block in bootstrap_htmx.html and make use of the row rednering template (plus clear pagination blocks):
{% block table.tbody %}
<tbody {{ table.attrs.tbody.as_html }}>
{% include 'bootstrap_tables_htmx_rows.html' %}
</tbody>
{% endblock table.tbody %}
{% block pagination.previous %}
{% endblock pagination.previous %}
{% block pagination.range %}
{% endblock pagination.range %}
{% block pagination.next %}
{% endblock pagination.next %}
In view check if htmx request is due to infinite scroll (lazy in request.GET) then only render rows. If htmx request is due to filter/sort update the render full table.
def get_template_names(self):
if self.request.htmx:
if "lazy" in self.request.GET:
# Render only rows
template_name = "bootstrap_tables_htmx_rows.html"
else:
# Render Full table
template_name = "product_table_partial.html"
else:
# Render full page
template_name = "product_table_htmx.html"
return template_name