custom pagination conversion to 2.x

custom pagination conversion to 2.x

mihomesmihomes Posts: 165Questions: 23Answers: 0

Converting things over to the new 2.x version (2.1.4 right now). I was previously using this custom pagination - not sure where I got it from. Basically, it would show the first, previous, pages, next, last for the pagination - the key was it would not show ellipsis and I could define a max number of actual page numbers to show (in this case set to three) and would always have the active page 'in the middle' if applicable.

So, say I am on page 50 out of 100... it would be first, previous, 49, 50, 51, next, last.

/* API method to get paging information */
$.fn.dataTableExt.oApi.fnPagingInfo = function (oSettings) {
    return {
        "iStart": oSettings._iDisplayStart,
        "iEnd": oSettings.fnDisplayEnd(),
        "iLength": oSettings._iDisplayLength,
        "iTotal": oSettings.fnRecordsTotal(),
        "iFilteredTotal": oSettings.fnRecordsDisplay(),
        "iPage": oSettings._iDisplayLength === -1 ?
            0 : Math.ceil(oSettings._iDisplayStart / oSettings._iDisplayLength),
        "iTotalPages": oSettings._iDisplayLength === -1 ?
            0 : Math.ceil(oSettings.fnRecordsDisplay() / oSettings._iDisplayLength)
    };
};

/* Bootstrap style full number pagination control */
$.extend($.fn.dataTableExt.oPagination, {
    "bootstrap_full_number": {
        "fnInit": function (oSettings, nPaging, fnDraw) {
            var oLang = oSettings.oLanguage.oPaginate;
            var fnClickHandler = function (e) {
                e.preventDefault();
                if (oSettings.oApi._fnPageChange(oSettings, e.data.action)) {
                    fnDraw(oSettings);
                }
            };

            $(nPaging).append(
                '<ul class="pagination ms-md-auto">' +
                '<li class="prev page-item disabled"><a class="page-link" href="#" title="' + oLang.sFirst + '"><i class="far fa-angle-double-left"></i></a></li>' +
                '<li class="prev page-item disabled"><a class="page-link" href="#" title="' + oLang.sPrevious + '"><i class="far fa-angle-left"></i></a></li>' +
                '<li class="next page-item disabled"><a class="page-link" href="#" title="' + oLang.sNext + '"><i class="far fa-angle-right"></i></a></li>' +
                '<li class="next page-item disabled"><a class="page-link" href="#" title="' + oLang.sLast + '"><i class="far fa-angle-double-right"></i></a></li>' +
                '</ul>'
            );
            var els = $('a', nPaging);
            $(els[0]).bind('click.DT', {
                action: "first"
            }, fnClickHandler);
            $(els[1]).bind('click.DT', {
                action: "previous"
            }, fnClickHandler);
            $(els[2]).bind('click.DT', {
                action: "next"
            }, fnClickHandler);
            $(els[3]).bind('click.DT', {
                action: "last"
            }, fnClickHandler);
        },

        "fnUpdate": function (oSettings, fnDraw) {
            var iListLength = 3;
            var iLen;
            var oPaging = oSettings.oInstance.fnPagingInfo();
            var an = oSettings.aanFeatures.p;
            var i, j, sClass, iStart, iEnd, iHalf = Math.floor(iListLength / 2);

            if (oPaging.iTotalPages < iListLength) {
                iStart = 1;
                iEnd = oPaging.iTotalPages;
            } else if (oPaging.iPage <= iHalf) {
                iStart = 1;
                iEnd = iListLength;
            } else if (oPaging.iPage >= (oPaging.iTotalPages - iHalf)) {
                iStart = oPaging.iTotalPages - iListLength + 1;
                iEnd = oPaging.iTotalPages;
            } else {
                iStart = oPaging.iPage - iHalf + 1;
                iEnd = iStart + iListLength - 1;
            }

            for (i = 0, iLen = an.length; i < iLen; i++) {
                if (oPaging.iTotalPages <= 0) {
                    $('.pagination', an[i]).css('visibility', 'hidden');
                } else {
                    $('.pagination', an[i]).css('visibility', 'visible');
                }

                // Remove the middle elements
                $('li:gt(1)', an[i]).filter(':not(.next)').remove();

                // Add the new list items and their event handlers
                for (j = iStart; j <= iEnd; j++) {
                    sClass = (j == oPaging.iPage + 1) ? 'class="page-item active"' : 'class="d-none d-sm-block"';
                    $('<li ' + sClass + '><a class="page-link" href="#">' + j + '</a></li>')
                        .insertBefore($('li.next:first', an[i])[0])
                        .bind('click', function (e) {
                            e.preventDefault();
                            oSettings._iDisplayStart = (parseInt($('a', this).text(), 10) - 1) * oPaging.iLength;
                            fnDraw(oSettings);
                        });
                }

                // Add / remove disabled classes from the static elements
                if (oPaging.iPage === 0) {
                    $('li.prev', an[i]).addClass('disabled');
                } else {
                    $('li.prev', an[i]).removeClass('disabled');
                }

                if (oPaging.iPage === oPaging.iTotalPages - 1 || oPaging.iTotalPages === 0) {
                    $('li.next', an[i]).addClass('disabled');
                } else {
                    $('li.next', an[i]).removeClass('disabled');
                }
            }
        }
    }
});

I found an example of extending the pagination for the new version in its bs5 js file. I made a few modifications already, but am missing the 'max page' part as I am not seeing a way to get total pages - it runs through each button one at a time. Also, it seems the default paging options are still applied no matter what I do... in other words it is doing the ellipsis stuff and I don't see a way to stop that. Also, correct me if I am wrong, but the new pagination also 'auto minimizes'... if that it the case, I would want to remove that feature as well in this situation. As you can see I handle that on my own.... if the page is not the active one I do not show it on small screens (only the active page along with the first, previous, next, last are shown).

Anyone mess around with anything like this on the new version? Without being familiar with the internal stuff of datatables I literally have no idea where to start on this.

DataTable.ext.renderer.pagingButton.bootstrap = function (settings, buttonType, content, active, disabled) {
    //testing
    //console.log('settings', settings);
    //console.log('buttonType', buttonType);
    //console.log('content', content);
    //console.log('active', active);
    //console.log('disabled', disabled);
    
    var btnClasses = ['page-item'];

    if (active) {
        btnClasses.push('active');
    }
        
    if (disabled) {
        btnClasses.push('disabled')
    }

        // hide non-active page buttons on small screen view
    if( !active && Number.isInteger(buttonType) ) {
        btnClasses.push('d-none d-sm-block');
    }
    
    var li = $('<li>').addClass(btnClasses.join(' '));
    var a = $('<button>', {
        'class': 'page-link',
        role: 'link',
        type: 'button',
        title: Number.isInteger(buttonType) ? '' : buttonType //only do titles on non number buttons (like first, previous, next, last)
    })
        .html(content)
        .appendTo(li);

    return {
        display: li,
        clicker: a
    };
};

DataTable.ext.renderer.pagingContainer.bootstrap = function (settings, buttonEls) {
    return $('<ul/>').addClass('pagination ms-md-auto').append(buttonEls);
};

Answers

  • allanallan Posts: 63,352Questions: 1Answers: 10,443 Site admin

    The paging controls were completely rewritten for v2 - the old plugins are unlikely to work (as you've found).

    The new paging control has a lot of options but disabling the ellipsis option is not one of them unfortunately. You can use paging.buttons to set the maximum number of numbered buttons, but for ellipsis it might need a modification to the core library.

    You could try:

    div.dt-paging span.ellipsis {
      display: none;
    }
    

    https://live.datatables.net/virobiqe/1/edit

    That might be enough?

    Allan

  • mihomesmihomes Posts: 165Questions: 23Answers: 0
    edited August 22

    Yeah, I already tried that and wasn't really happy with the results. I can do it by checking the buttonType in the code I provided above and then just set a display none class to it. Which does the job same as your example... but the active page button isn't centered in the list and when using the 'buttons: 3' for example in the paging options it is still going to count the ellipses (if there are any) in the count.

    So am I correct that extending the pagination like the new style code example I gave is always going to be 'overwritten' by the default pagination functionality? Like we can't create our own pagination 'style' like before that doesn't have anything 'extra' applied to its behavior? No built-in responsive actions, no ellipsis, etc... just create the pagination from scratch and add responsive stuff and what not on our own?

  • mihomesmihomes Posts: 165Questions: 23Answers: 0

    Kind of related... is there no way to set pagination default options using https://github.com/DataTables/DataTablesSrc/blob/master/js/ext/ext.classes.js?

    Something like :

    $.extend( DataTable.ext.classes, {
        container: 'dt-container',
        pagination: {
            buttons: 3
        },
        layout: {
            row: 'dt-layout-row',
            cell: 'dt-layout-cell',
            tableRow: 'dt-layout-table',
            tableCell: 'dt-table table-responsive',
            start: 'dt-layout-start',
            end: 'dt-layout-end',
            full: 'dt-layout-full',
        },
            ...and so on
    
  • mihomesmihomes Posts: 165Questions: 23Answers: 0
    edited August 22

    As for the ellipsis stuff... is it possible you could only count 'visible' buttons in the pagination coding? That would at least solve the `buttons: x' option to behave as one expects. I don't think you'd have any one complaining about hidden buttons not being counted.

  • mihomesmihomes Posts: 165Questions: 23Answers: 0

    Updating this... I ended up modifying the core js function _pagingNumbers with the following logic :

            if ( pages <= buttons ) {
                numbers = _range(0, pages);
            }
            else if ( page <= half ) {
                numbers = _range(0, buttons);
            }
            else if ( page >= pages - half ) {
                numbers = _range(pages - buttons, pages);
            }
            else {
                numbers = _range(page - half, page + half + 1);
            }
    

    Appears to work as expected through a few different tests. Note that the addFirstLast setting no longer has any bearing since we aren't showing the ellipses. The only problem I can see happening is if other logic won't have the correct button count now - I'm assuming that won't be an issue though.

    Still wondering about setting default pagination options with $.extend( DataTable.ext.classes, {...}) though. Not sure if I am doing something wrong or not, but it seems like the only way to set the pagination options is when I init a datatable (dataTable.DataTable({...})).

  • allanallan Posts: 63,352Questions: 1Answers: 10,443 Site admin

    Hi,

    Thanks for the follow ups! The old pagination API is basically dead now (I did use part of it for rendering the buttons in different styles for Bootstrap etc, which is why it might look like there are parts still there).

    The paging control is now a built in feature and the idea with it was that it should be flexible enough for basic paging controls (and work with the different styling frameworks using the same logic). The upshot was that if a different way of controlling the paging of the table was needed, then a new feature plug-in would need to be created (for example the input paging plugin).

    Each part of the built in paging feature I would like to be configurable, so I think being able to turn the ellipsis off would be a good thing to add, and I've added it to my feature "todo" list.

    The reason the ellipsis are counted as buttons is that they take up the space of one button - so really the buttons parameter for the feature is the amount of space that can be taken up. Changing that I would consider to be a backwards compatibility issue since some will be using it specifically that way.

    Its a very good point about setting defaults for the features - that is something that I have overlooked and my apologies for that. I've added that to the bug todo list!

    Regards,
    Allan

  • mihomesmihomes Posts: 165Questions: 23Answers: 0

    Thanks Allan. I just went through about 150 or so pages and changed 'dom' settings to the new 'layout' settings. That was one reason I was asking about settings defaults for the pagination. Everything seems to be working fine.

    One scenario that came to mind, and surprisingly did not affect me, was chaining divs in the new layout settings. For example, I have a few cases where I need to do the following :

        var dt = dataTable.DataTable({
            "layout": {
                "top": null,
                "topStart": null,
                "topEnd": null,
                "bottom": {
                    "className": 'dtFooter short',
                    "features": [{
                        "info": {},
                        "paging": {
                            "buttons" : 3
                        },
                        "div": {
                            "className": 'dtInfoPost2'
                        },
                    }]
                },
                "bottomStart":null,
                "bottomEnd": null,
            },
    

    Would something like this be possible? Like I said, I didn't actually have a case in my current code where this came up, but I was kind of shocked I didn't. I know the old 'dom' way let you do any number of chaining/levels.

    If not, I suppose one could just set the div entry's html value to do this, but this would also eliminate adding any of the 'features' like paging, info, search, etc past one level deep.

        var dt = dataTable.DataTable({
            "layout": {
                "top": null,
                "topStart": null,
                "topEnd": null,
                "bottom": {
                    "className": 'dtFooter short',
                    "features": [{
                        "info": {},
                        "paging": {
                            "buttons" : 3
                        },
                        "div": {
                            "className": 'dtInfoPost2',
                            "features": [{
                                "paging": {
                                    "buttons" : 3
                                },
                                "div": {
                                    "className": 'dtInfoPost3'
                                }
                            }]
                        },
                    }]
                },
                "bottomStart":null,
                "bottomEnd": null,
            },
    
  • allanallan Posts: 63,352Questions: 1Answers: 10,443 Site admin

    At the moment no. I did wonder about providing some way of doing that with the div feature (allowing features inside it), but I wasn't able to cook up any use cases that would warrent the extra complexity, so I decided to park it and wait to see if there were any requests for it. I'll chalk one up on the board :)

    Allan

Sign In or Register to comment.