Adding Pagination to table in Back office

Hi,

Can any one point me in the direction of how to add pagination to a uui-table in the back office.

I have it loading data but I need to paginate it.

Regards

Darren

I used AI to create a minimal example based on a dashboard where I use paging in a uui-table. It also features a dropdown to select the page size. Hope it helps!

It’s a matter of using a uui-pagination and keeping track of pages and page size and request your data paged from an API endpoint. You just need to handle a few events, but that’s it.

import { LitElement, html, state, customElement } from "@umbraco-cms/backoffice/external/lit";

/**
 * Minimal paging example for form posts
 */
@customElement('minimal-paged-form')
export default class MinimalPagedFormElement extends LitElement {

    // Page size options
    private readonly PAGE_SIZE_OPTIONS: number[] = [10, 25, 50];
    private readonly DEFAULT_PAGE_SIZE: number = 25;

    // Pagination state
    @state()
    private _currentPage = 1;

    @state()
    private _pageSize = this.DEFAULT_PAGE_SIZE;

    @state()
    private _totalPages = 0;

    @state()
    private _totalItems = 0;

    @state()
    private _data: any[] = [];

    @state()
    private _isLoading = false;

    async connectedCallback() {
        super.connectedCallback();
        await this.#loadData();
    }

    /**
     * Load paged data from API
     */
    async #loadData(): Promise<void> {
        this._isLoading = true;
        try {
            // Calculate skip value for API
            const skip = (this._currentPage - 1) * this._pageSize;
            
            // Example API call structure (replace with your actual endpoint)
            const response = await fetch('/api/your-endpoint', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    skip: skip,
                    take: this._pageSize
                    // Add other filters/parameters as needed
                })
            });

            const result = await response.json();
            
            // Update state with results
            this._data = result.items || [];
            this._totalItems = result.totalCount || 0;
            this._totalPages = Math.ceil(this._totalItems / this._pageSize);

        } catch (error) {
            console.error("Failed to load data", error);
        } finally {
            this._isLoading = false;
        }
    }

    /**
     * Handle page change from pagination component
     */
    async #onPageChange(event: CustomEvent): Promise<void> {
        this._currentPage = event.detail?.current || 1;
        await this.#loadData();
    }

    /**
     * Handle page size change
     */
    async #onPageSizeChange(newSize: number): Promise<void> {
        this._pageSize = newSize;
        
        // Recalculate total pages and adjust current page if needed
        const newTotalPages = Math.ceil(this._totalItems / newSize);
        this._currentPage = Math.min(this._currentPage, Math.max(1, newTotalPages));
        
        await this.#loadData();
    }

    render() {
        return html`
            <div class="container">
                ${this._isLoading 
                    ? html`<uui-loader></uui-loader>`
                    : html`
                        <!-- Your data display here -->
                        <div class="data">
                            ${this._data.map(item => html`<div>${item}</div>`)}
                        </div>

                        <!-- Pager -->
                        <div class="pager-container">
                            <!-- Page size selector -->
                            <div class="page-size">
                                Results per page:
                                ${this.PAGE_SIZE_OPTIONS.map((size, index) => html`
                                    ${index > 0 ? html`<span>|</span>` : ''}
                                    <uui-button 
                                        compact 
                                        .look="${this._pageSize === size ? 'primary' : 'default'}"
                                        @click="${() => this.#onPageSizeChange(size)}">
                                        ${size}
                                    </uui-button>
                                `)}
                            </div>

                            <!-- Pagination component -->
                            <uui-pagination
                                .current="${this._currentPage}"
                                .total="${this._totalPages}"
                                @change="${this.#onPageChange}">
                            </uui-pagination>
                        </div>
                    `
                }
            </div>
        `;
    }
}

declare global {
    interface HTMLElementTagNameMap {
        'minimal-paged-form': MinimalPagedFormElement;
    }
}

Thank you for your help.

There are a few examples in the umbraco-cms source.. not necessarily tables but lists with pagination and seem to follow the same pattern..

eg
Umbraco-CMS/src/Umbraco.Web.UI.Client/src/packages/media/media/audit-log/info-app/media-history-workspace-info-app.element.ts at main · umbraco/Umbraco-CMS