Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Merge new filter function with existing pagination and filter jQuery/Javascript

I'm having a problem with my new table filtering function, the problem happens when selecting an offer to filter by - rather than showing the rows from all the filterable data inside the table the filter filters the visible rows only minus the data hidden by pagination.

On top of that when I click more to show more rows the table starts showing data outside the current filter. Which is not good.

I also have another filtering function to filter by "Free Handsets" which has been combined with my pagination method (Code below).

How can I merge this filter (the dropdown one) with my "Free Handsets" filter (the checkbox one) and pagination method, so that when I select an option to filter by the filter deals with all the data inside the table and not just the visible rows being displayed by pagination.

https://jsfiddle.net/51Le6o06/48/

The fiddle above shows both filtering functions working side by side but they don't function well together.

As you can see in the above jsfiddle the dropdown filter collects its options from the HTML then presents them in the dropdown menu, so all options are present to be filtered by there just hidden by pagination.

Here is the jQuery and Javascript for each of the functions.

This is the new filter that doesn't function well.

$(document).ready(function() {
    $('.filter-gift').each(filterItems);
});

function filterItems(e) {
    var items = [];
    var table = '';
    tableId = $(this).parent().parent().attr('tag')

      var listItems = "";
        listItems += "<option value=''> -Select- </option>";
        $('div[tag="' + tableId + '"] table.internalActivities .information').each(function (i) {
            var itm = $(this)[0].innerText;
            if ($.inArray(itm, items) == -1) {
                items.push($(this)[0].innerText);
                listItems += "<option value='" + i + "'>" + $(this)[0].innerText + "</option>";
            }
        });

    $('div[tag="' + tableId+ '"] .filter-gift').html(listItems);

    $('.filter-gift').change(function () {
    if($(this).val()!= "") {
        var tableIdC = $(this).parent().parent().attr('tag');

        var text = $('div[tag="' + tableIdC + '"] select option:selected')[0].text.replace(/(\r\n|\n|\r| |)/gm, "");;
            $('div[tag="' + tableIdC + '"] .product-information-row').each(function (i) {
                if ($(this).text().replace(/(\r\n|\n|\r| |)/gm, "") == text) {
                    $(this).show();
                    $(this).prev().show();
                    $(this).next().show();
                }
                else {
                    $(this).hide();
                    $(this).prev().hide();
                    $(this).next().hide();
                }
            }); 
            } else {
            $(this).parent().parent().find('table tr').show();
            }
        });     
}

This is the filter and pagination function I want to merge with the above function (working).

jQuery.fn.sortPaging = function(options) {
    var defaults = {
        pageRows: 2
    };
    var settings = $.extend(true, defaults, options);
    return this.each(function() {

        var container = $(this);
        var tableBody = container.find('.internalActivities > tbody');
        var dataRows = [];
        var currentPage = 1;
        var maxPages = 1;
        var buttonMore = container.find('.seeMoreRecords');
        var buttonLess = container.find('.seeLessRecords');
        var buttonFree = container.find('.filter-free');
        var tableRows = [];
        var maxFree = 0;
        var filterFree = buttonFree.is(':checked');
        function displayRows() {
            tableBody.empty();
            var displayed = 0;
            $.each(dataRows, function(i, ele) {
                if( !filterFree || (filterFree && ele.isFree) ) {
                    tableBody.append(ele.thisRow).append(ele.nextRow);
                    displayed++;
                    if( displayed >= currentPage*settings.pageRows ) {
                        return false;
                    };
                };
            });
        };
        function checkButtons() {
            buttonLess.toggleClass('element_invisible', currentPage<=1);
            buttonMore.toggleClass('element_invisible', filterFree ? currentPage>=maxFreePages : currentPage>=maxPages);
        };
        function showMore() {
            currentPage++;
            displayRows();
            checkButtons();
        };
        function showLess() {
            currentPage--;
            displayRows();
            checkButtons();
        };
        function changedFree() {
            filterFree = buttonFree.is(':checked');
            if( filterFree && currentPage>maxFreePages ) {
                currentPage=maxFreePages;
            };
            displayRows();
            checkButtons();
        };

        tableBody.find('.product-data-row').each(function(i, j) {
            var thisRow = $(this);
            var nextRow = thisRow.next();
            var amount = parseFloat(thisRow.find('.amount').text().replace(/£/, ''));
            var isFree = thisRow.find('.free').length;
            maxFree += isFree;
            dataRows.push({
                amount: amount,
                thisRow: thisRow,
                nextRow: nextRow,
                isFree: isFree
            });
        })

        dataRows.sort(function(a, b) {
            return a.amount - b.amount;
        });
        maxPages = Math.ceil(dataRows.length/settings.pageRows);
        maxFreePages = Math.ceil(maxFree/settings.pageRows);

        tableRows = tableBody.find("tr");

        buttonMore.on('click', showMore);
        buttonLess.on('click', showLess);
        buttonFree.on('change', changedFree);

        displayRows();
        checkButtons();

    })

};

$('.sort_paging').sortPaging();

Goals

  • Make filter work with work with pagination.
  • Make filter work simultaneously with "Free Handset" filter.
like image 939
mitchelangelo Avatar asked May 08 '16 22:05

mitchelangelo


2 Answers

Your code is needlessly complicated. try to break it down into the necessary steps. About your essential problem: do everything in one go (read below to fully understand my approach):

function onFilterChange() {
    filterProducts();
    resetPagination();
    showNextPage();
}

also improve your data structure:

if you use html as your data source, use attributes in your main objects, that will make it easy to find them. use multiple tbody tags to group your trs:

<tbody freeTv='false' freeHandset='false' cost='200'>
    <tr>
        <td>content of product 1</td>
    </tr>
    <tr>
        <td>description of product 1</td>
    </tr>
</tbody>
<tbody freeTv='true' freeHandset='false' cost='300'>
    <tr>
        <td>content of product 2</td>
    </tr>
    <tr>
        <td>description of product 2</td>
    </tr>
</tbody>

i prefer to add classes to my elements instead of removing/adding the whole element. be aware though that this will make a mess if you are planning to use nth-css-styling. if you dont need that its a great, well-debuggable way to add interaction:

function filterProducts() {
    $('tbody').addClass('filtered');
    // ... some domain-specific magic here ...
    $('tbody[freeTv="true"]').removeClass('filtered');
}

now you just need a .filtered css definition like:

.filtered { display: none; }

for pagination you can act in a similar fashion. first hide everything (again with css .paged { display: none; } ):

function resetPagination() {
    $('tbody').addClass('paged');
    $('tbody.filtered').removeClass('paged');
}

then show the ones you want (the first 10 paged ones):

function showNextPage() {
    $('tbody.paged').slice(0, 10).removeClass('paged');
}

https://jsfiddle.net/g9zt0fan/

like image 136
ZPiDER Avatar answered Sep 21 '22 23:09

ZPiDER


I solved the problem myself by starting from scratch and using the datatables library. I'm still working on it but the code is a lot simpler to deal with.

The only problem I face now is changing the pagination style.

https://jsfiddle.net/6k0bshb6/16/

// This function is for displaying data from HTML "data-child-value" tag in the Child Row.
function format(value) {
      return '<div>Hidden Value: ' + value + '</div>';
  }

// Initialization of dataTable and settings.
  $(document).ready(function () {
      var dataTable = $('#example').DataTable({
       bLengthChange: false,
       "pageLength": 5,
       "pagingType": "simple",
       "order": [[ 7, "asc" ]],
       "columnDefs": [
            {
                "targets": [ 5 ],
                "visible": false,
                "searchable": true
            },
            {
                "targets": [ 6 ],
                "visible": false,
                "searchable": true
            },
            {
                "targets": [ 7 ],
                "visible": false,
                "searchable": true
            }
        ],

// Dropdown filter function for dataTable from hidden column number 5 for filtering gifts.
       initComplete: function () {
            this.api().columns(5).every(function () {
                var column = this;
                var select = $('<select><option value="">Show all</option></select>')
                    .appendTo($("#control-panel").find("div").eq(1))
                    .on('change', function () {
                    var val = $.fn.dataTable.util.escapeRegex(
                    $(this).val());
                    column.search(val ? '^' + val + '$' : '', true, false)
                        .draw();
                });
                column.data().unique().sort().each(function (d, j) {
                    select.append('<option value="' + d + '">' + d + '</option>')
                });
            });
        }
    });

// This function is for handling Child Rows.
    $('#example').on('click', 'td.details-control', function () {
          var tr = $(this).closest('tr');
          var row = dataTable.row(tr);

          if (row.child.isShown()) {
              // This row is already open - close it
              row.child.hide();
              tr.removeClass('shown');
          } else {
              // Open this row
              row.child(format(tr.data('child-value'))).show();
              tr.addClass('shown');
          }
    });

// Checkbox filter function below is for filtering hidden column 6 to show Free Handsets only.
    $('#checkbox-filter').on('change', function() {
        dataTable.draw();
    });

    $.fn.dataTable.ext.search.push(
      function( settings, data, dataIndex ) {
        var target = '£0.00';
        var position = data[6]; // use data for the position column
        if($('#checkbox-filter').is(":checked")) {
            if (target === position) {
            return true;
         }
         return false;
        }
        return true;
      }
    );
});
like image 40
mitchelangelo Avatar answered Sep 24 '22 23:09

mitchelangelo