Page size selector in iommi tables

This is an example of how you can offer your visitors to change page_size of your iommi Tables.

iommi.page-size-selector

iommi is a library for making forms, tables and more in your django projects, much better than the django built-in CBV's. If you don't use it yet, you should check it out.

I'm going to assume in this article that you already know django, iommi and that you have some general knowledge of web development.

First you need to make a custom templates/iommi_paginator.html

<div class="row mt-10">
    <div class="col-1">
        <select class="form-select w-auto page-size-choices" name="{{ paginator.iommi_path }}_size">
            {% with '10 20 30 50 100' as size_choices %}
            {% for value in size_choices.split %}
            <option value="{{ value }}"{% if value == paginator.page_size|stringformat:"i" %} selected{% endif %}>{{ value }}</option>
            {% endfor %}
            {% endwith %}
        </select>
    </div>
    <div class="col">
    	{# include the iommi paginator.html you're using #}
        {% include "iommi/table/bootstrap/paginator.html" %}
    </div>
</div>

Then you're going to need a JS

(put this in your main.js or whatever you have)

function initPageSizeSelectors(event) {
    let parent;
    if(event) {
        parent = event.target;
    } else {
        parent = document;
    }

    parent.querySelectorAll(".page-size-choices:not(.bound)").forEach(function (field) {
        field.addEventListener("change", function() {
            let params = new URL(window.location.href).searchParams;
            params.set(field.name, field.value);
            window.history.replaceState(null, null, `${window.location.pathname}?${params.toString()}`);
            field.closest('.iommi-table-container').iommi.reload();
            field.classList.add("bound");
        });
    });
}

["iommi.init.end", "iommi.element.populated"].forEach(eventType => {
    document.addEventListener(eventType, initPageSizeSelectors);
});

Now add to your custom iommi style

def get_page_size(request, table, **kwargs):
    session_page_size = request.session.get('iommi_table_page_size')
    page_size = None

    # cannot get table.paginator.iommi_path here, it's too soon
    param_name = 'page_size'
    if table.iommi_path:
        param_name = f'{table.iommi_path}/{param_name}'
    if (page_size_str := request.GET.get(param_name)) is not None:
        try:
            page_size = int(page_size_str)
        except ValueError:
            pass

    if page_size:
        if page_size != session_page_size:
            request.session['iommi_table_page_size'] = page_size
        return page_size

    return session_page_size or 20


my_style = Style(
    # ...
    Paginator__template="iommi_paginator.html",
    Table__page_size=get_page_size,
    # ...
)

And that's all. Now you have a page_size selector on all tables. It does remember the visitor's choice, so all your tables respect the selected value.
You could also save it to the User model, if you want it more permanent. Also you could save it per Table, if you include (for example) table.__class__.__name__ in the session key.

And you can turn it off on some tables with:

class FixedTable(iommi.Table):
    class Meta:
        extra__hide_page_size_selector = True
        page_size = 30
        # ...