'LWC Pagination with page number

I'm a junior developer, I need some help to implement an lwc component which display records in experience site so I need to implement pagination since we have a large number to record.

I implement the 2 buttons "Previous" and "Next" it works fine, but I need the a clickable number o page between the 2 buttons here is the mockup : something like :<- 1 2 3 4 ... ->

here is my code:

<template>
    <div class="pastcfps"><br>
        <table>
            <thead>
                <tr>
                    <th class="pastcfpstitle"></th>  
                    <th class="fullProposalDeadlineTitle"><a data-id="Proposal_Submission_Deadline__c"
                            onclick={sort}>Closing Date<img src={sortArrowUp} data-id="sortIconFp"></a></th>
                </tr>
            </thead>
            <tbody>
                <template if:true={pastcfps}>
                    <template for:each={pastcfps} for:item="pastcfp">
                        <tr class="pastcfpstr" key={pastcfp.Id}>
                            <td key={pastcfp.Id} class="pastcfpstitle">
                                <p class="pastcfpsRecordType">{pastcfp.RecordType.Name}</p>
                                <a class="pastcfpsname" data-id={pastcfp.Id} onclick={redirect} is-loading={tableLoadingState}>{pastcfp.Name}</a>
                            </td>
                            <td key={pastcfp.Id} class="fullProposalDeadline">{pastcfp.Proposal_Submission_Deadline__c}
                            </td>
                        </tr>
                    </template>
                </template>
            </tbody>
            <template if:true={error}>
                <p class="pastcfpsname">There are no past Calls for Proposals</p>
            </template>
        </table>
    </div>
    <div style="text-align:center;">
        <c-pagination-navigation onprevious={handlePrev} onnext={handleNext}></c-pagination-navigation>
    </div>
    
</template>

import { LightningElement, api, wire, track } from 'lwc';
import getPastCfPs from '@salesforce/apex/CallsForProposalsService.getPastCfPs';
import ARROW_LOGO from '@salesforce/contentAssetUrl/homearrow';
import SORT_ARROW_UP from '@salesforce/resourceUrl/sortArrowUp';
import SORT_ARROW_DOWN from '@salesforce/resourceUrl/sortArrowDown';



export default class RecentOpenCallsForProposals extends LightningElement {

    arrowLogo = ARROW_LOGO;
    sortArrowUp = SORT_ARROW_UP;
    sortArrowDown = SORT_ARROW_DOWN;
    sortedDirection = 'asc';
    sortedColumn;
    @track tableLoadingState = false;
    @track pastcfps;
    @track error
    @track offset=0;
    @track Prevoffset=0;
    limit = 12;

    

    @wire(getPastCfPs,{ offset: '$offset', l : '$limit' }) wiredCfps({ data, error }) {
       
        this.tableLoadingState = false;
        if (data) {
            this.pastcfps = data;
            console.log(' type of data =====| ' + typeof data);
            console.log(' type of data 0 =====| ' + typeof data[0]);
            console.log(' type of data =====| ' + typeof this.pastcfps);
            console.log(' type of data 0 =====| ' + typeof this.pastcfps[0]);
            let dataString = JSON.stringify(data[0]);
            console.log(' dataString ========| ' + dataString);

                console.log(' Name ========| ' + data[0].Name);
                console.log(' Status__c ========| ' + data[0].Status__c);
                console.log(' CreatedDate ========| ' + data[0].CreatedDate);
                console.log(' Proposal_Submission_Deadline__c ========| ' + data[0].Proposal_Submission_Deadline__c);

                        
            this.error = undefined;
            if(this.pastcfps.length == 0)
                this.offset= this.Prevoffset;
        } else if (error) {
            this.error = error;
            this.pastcfps = undefined;
        }

    }

    handlePrev (_event) {
        //window.clearTimeout(this.delayTimeout);        
        if(this.offset - this.limit >=0)
        {
            this.tableLoadingState = true;
            this.Prevoffset=this.offset;
            this.offset = this.offset - this.limit;
        }
    }

    handleNext (_event) {
        //window.clearTimeout(this.delayTimeout);
        this.tableLoadingState = true;
        this.Prevoffset=this.offset;
        this.offset = this.offset + this.limit;
    }


    redirect(event) {
        var id = event.currentTarget.dataset.id;
        if (id) {
            window.location = 'call-for-proposal/' + id;
        }
    }

    sort(e) {
        if (this.sortedColumn === e.currentTarget.dataset.id) {
            this.sortedDirection = this.sortedDirection === 'asc' ? 'desc' : 'asc';
        } else {
            this.sortedDirection = 'asc';
        }
        let table = JSON.parse(JSON.stringify(this.pastcfps));
        var reverse = this.sortedDirection === 'asc' ? 1 : -1;
        try {
            table.sort((a, b) => { return new Date(a[e.currentTarget.dataset.id]) > new Date(b[e.currentTarget.dataset.id]) ? 1 * reverse : -1 * reverse });
        } catch (error) {
            console.log(error);
        }
        this.sortedColumn = e.currentTarget.dataset.id;
        this.pastcfps = table;


    if (e.currentTarget.dataset.id == 'Proposal_Submission_Deadline__c') {
            let existingIcon = this.template.querySelectorAll('img[data-id="sortIconFp"]');
            if (existingIcon[0]) {
                existingIcon[0].parentNode.removeChild(existingIcon[0]);
            }
            let nodes = this.template.querySelectorAll('a[data-id="' + e.currentTarget.dataset.id + '"]');
            var icon = document.createElement('IMG');
            if (this.sortedDirection === 'asc') { icon.setAttribute('src', this.sortArrowUp); }
            if (this.sortedDirection === 'desc') { icon.setAttribute('src', this.sortArrowDown); }
            icon.setAttribute('data-id', 'sortIconFp');
            if (nodes[0]) { nodes[0].appendChild(icon); }
        }
    }

}

@AuraEnabled(cacheable=true)
    public static List<Call_for_Proposal__c> getPastCfPs(Integer offset, Integer l){
        String recordTypeName = [SELECT Id, Name, Status__c, CreatedDate, RecordTypeId, RecordType.Name, Proposal_Submission_Deadline__c FROM Call_for_Proposal__c WHERE  Status__c = 'Closed'  ].get(0).RecordType.Name;
        system.debug('recordTypeName === ' + recordTypeName);
        return [SELECT Id, Name, Status__c, CreatedDate, RecordTypeId, RecordType.Name, Proposal_Submission_Deadline__c FROM Call_for_Proposal__c WHERE  Status__c = 'Closed'  limit :l  offset :offset];
    }


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source