Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Datatables with column filter dropdowns and multiple checkbox selection

I found this excellent code from joao vitor retamero - fiddle: https://jsfiddle.net/jvretamero/bv6g0r64/ that shows how to make multiple selections in jquery datatable column filters. But I need to transform the filter containers into dropdowns, with each item in the container being a checkbox. Yes, there are many references to this, as I've found out during several hours of researching. But I'm yet to find any examples, or any clear explanations of how to do this, despite many saying it's possible with jquery plugin. Can anyone point to any examples? I've no clue how to even start. Many thanks.

<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://cdn.datatables.net/1.10.16/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.10.16/css/jquery.dataTables.min.css"></script>

    $(document).ready(function() {
    $('#example').DataTable( {
        initComplete: function () {
            this.api().columns().every( function () {
                var column = this;
                var select = $('<select multiple="multiple"><option value=""></option></select>')
                    .appendTo( $(column.footer()).empty() )
                    .on( 'change', function () {
                        var vals = $('option:selected', this).map(function (index, element) {
                            return $.fn.dataTable.util.escapeRegex($(element).val());
                        }).toArray().join('|');

                        column
                            .search( vals.length > 0 ? '^('+vals+')$' : '', true, false )
                            .draw();
                    } );

                column.data().unique().sort().each( function ( d, j ) {
                    select.append( '<option value="'+d+'">'+d+'</option>' )
                } );
            } );
        }
    } );
} );
like image 450
Silverburch Avatar asked Apr 15 '18 20:04

Silverburch


Video Answer


3 Answers

Try this, which doesn't use any extra JS/jQuery libraries:

// This code has been beautified via http://jsbeautifier.org/ with 2 spaces indentation.
$(document).ready(function() {
  function cbDropdown(column) {
    return $('<ul>', {
      'class': 'cb-dropdown'
    }).appendTo($('<div>', {
      'class': 'cb-dropdown-wrap'
    }).appendTo(column));
  }

  $('#example').DataTable({
    initComplete: function() {
      this.api().columns().every(function() {
        var column = this;
        var ddmenu = cbDropdown($(column.header()))
          .on('change', ':checkbox', function() {
            var active;
            var vals = $(':checked', ddmenu).map(function(index, element) {
              active = true;
              return $.fn.dataTable.util.escapeRegex($(element).val());
            }).toArray().join('|');

            column
              .search(vals.length > 0 ? '^(' + vals + ')$' : '', true, false)
              .draw();

            // Highlight the current item if selected.
            if (this.checked) {
              $(this).closest('li').addClass('active');
            } else {
              $(this).closest('li').removeClass('active');
            }

            // Highlight the current filter if selected.
            var active2 = ddmenu.parent().is('.active');
            if (active && !active2) {
              ddmenu.parent().addClass('active');
            } else if (!active && active2) {
              ddmenu.parent().removeClass('active');
            }
          });

        column.data().unique().sort().each(function(d, j) {
          var // wrapped
            $label = $('<label>'),
            $text = $('<span>', {
              text: d
            }),
            $cb = $('<input>', {
              type: 'checkbox',
              value: d
            });

          $text.appendTo($label);
          $cb.appendTo($label);

          ddmenu.append($('<li>').append($label));
        });
      });
    }
  });
});

CSS

/* Styles for the drop-down. Feel free to change the styles to suit your website. :-) */

.cb-dropdown-wrap {
  max-height: 80px; /* At most, around 3/4 visible items. */
  position: relative;
  height: 19px;
}

.cb-dropdown,
.cb-dropdown li {
  margin: 0;
  padding: 0;
  list-style: none;
}

.cb-dropdown {
  position: absolute;
  z-index: 1;
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: #fff;
  border: 1px solid #888;
}

/* For selected filter. */
.active .cb-dropdown {
  background: pink;
}

.cb-dropdown-wrap:hover .cb-dropdown {
  height: 80px;
  overflow: auto;
  transition: 0.2s height ease-in-out;
}

/* For selected items. */
.cb-dropdown li.active {
  background: #ff0;
}

.cb-dropdown li label {
  display: block;
  position: relative;
  cursor: pointer;
  line-height: 19px; /* Match height of .cb-dropdown-wrap */
}

.cb-dropdown li label > input {
  position: absolute;
  right: 0;
  top: 0;
  width: 16px;
}

.cb-dropdown li label > span {
  display: block;
  margin-left: 3px;
  margin-right: 20px; /* At least, width of the checkbox. */
  font-family: sans-serif;
  font-size: 0.8em;
  font-weight: normal;
  text-align: left;
}

/* This fixes the vertical aligning of the sorting icon. */
table.dataTable thead .sorting,
table.dataTable thead .sorting_asc,
table.dataTable thead .sorting_desc,
table.dataTable thead .sorting_asc_disabled,
table.dataTable thead .sorting_desc_disabled {
  background-position: 100% 10px;
}

Demo

https://jsfiddle.net/41vgefnf/1/
https://jsfiddle.net/41vgefnf/6/
https://jsfiddle.net/41vgefnf/8/
https://jsfiddle.net/41vgefnf/9/
https://jsfiddle.net/41vgefnf/10/

UPDATE

I moved the filter dropdowns to the header, and styled the dropdowns to look more like dropdown menus. (No JS or jQuery involved in the dropdown functionality; just pure CSS with basic animation — CSS3 transition.)

UPDATE #2

Sorry, I forgot apply the CSS "active" class to selected items.

UPDATE #3

Same like Update #2 case, but for the dropdown menu wrapper. (Sorry for keep forgetting things.. and I edited just to conform/meet to the requirements/changes you've actually requested. :) But I think this update would be the final revision.)

UPDATE #4

Fixed the "active" state change of the dropdown menu wrapper.

CREDITS

Thank you @Giacomo for your Fiddle. =)

like image 95
Sally CJ Avatar answered Oct 13 '22 08:10

Sally CJ


I think what you are searching for in user interface terms is a multiselect.

It doesn't actually exist a dropdown element with multiple selection using a checkbox (multiselect already exists for that kind of interaction need).

I think you need a custom multiselect with better user experience (not the default one like in example provided).

Here is a fiddle with my purpose, i understand that this is not exactly what you were asking for, but i pretty think this will suite your request at a more abstract level.

All i did is to use a jquery plugin called select2, very usefull to enhance ux and ui in various input elements.

Please check code comments for technicalities.

https://jsfiddle.net/p1261jby/3/

/*added as resources
https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/js/select2.min.js
https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/css/select2.min.css
*/

$(document).ready(function() {
  $('#example').DataTable({
    initComplete: function() {
      this.api().columns().every(function() {
        var column = this;
        //added class "mymsel"
        var select = $('<select class="mymsel" multiple="multiple"><option value=""></option></select>')
          .appendTo($(column.footer()).empty())
          .on('change', function() {
            var vals = $('option:selected', this).map(function(index, element) {
              return $.fn.dataTable.util.escapeRegex($(element).val());
            }).toArray().join('|');

            column
              .search(vals.length > 0 ? '^(' + vals + ')$' : '', true, false)
              .draw();
          });

        column.data().unique().sort().each(function(d, j) {
          select.append('<option value="' + d + '">' + d + '</option>')
        });
      });
      //select2 init for .mymsel class
      $(".mymsel").select2();
    }
  });
});

Here are Select2 docs in case you need to customize some parameters. https://select2.org/selections

like image 8
Giacomo Penuti Avatar answered Oct 13 '22 09:10

Giacomo Penuti


Here's another flavour. It's using modified code from Elmahdi Mahmoud for the multi-select, so I've left in his MIT copyright message.

I'll warn you now, the code isn't pretty, but the result is effective, so I thought it worth adding to the pile of options. A live fiddle is here.

The JS is

    /* Plugin API method to determine is a column is sortable */
$.fn.dataTable.Api.register('column().searchable()', function() {
  var ctx = this.context[0];
  return ctx.aoColumns[this[0]].bSearchable;
});


$(document).ready(function() {
  // Create the DataTable
  var table = $('#example').DataTable({
    fixedHeader: true,
    pageLength: 25,
    orderCellsTop: true,
    columnDefs: [{
      searchable: false,
      targets: [0, 4]
    }],
  });

  // Add filtering
  table.columns().every(function() {
    if (this.searchable()) {
      var that = this;


      var myList = $('<ul/>');
      var myMulti = $('<div class="mutliSelect"/>');
      myList.appendTo(myMulti);

      var myDd = $('<dd/>');
      myMulti.appendTo(myDd);

      var myDropdown = $('<dl class="dropdown"/>');
      myDropdown.append('<dt><a href="#"><span class="hida">Select</span><p class="multiSel"></p></a></dt>');
      myDd.appendTo(myDropdown);

      myDropdown
        .appendTo(
          $('thead tr:eq(1) td').eq(this.index())
        )
        .on('change', function() {
          var vals = $(':checked', this).map(function(index, element) {
            return $.fn.dataTable.util.escapeRegex($(element).val());
          }).toArray().join('|');

          that
            .search(vals.length > 0 ? '^(' + vals + ')$' : '', true, false)
            .draw();
        });


      // Add data
      this
        .data()
        .sort()
        .unique()
        .each(function(d) {
          myList.append($('<li><input type="checkbox" value="' + d + '"/>' + d + '</option>'));
        });

    }
  });


  /*
    Dropdown with Multiple checkbox select with jQuery - May 27, 2013
    (c) 2013 @ElmahdiMahmoud
    license: https://www.opensource.org/licenses/mit-license.php
  */

  $(".dropdown dt a").on('click', function(e) {
    var dropdown = $(this).closest('.dropdown');
    dropdown.find('ul').slideToggle('fast');

    $('.dropdown').not(dropdown).find('ul').slideUp('fast');

  });

  $(".dropdown dd ul li a").on('click', function() {
    $(".dropdown dd ul").hide();
  });

  function getSelectedValue(id) {
    return $("#" + id).find("dt a span.value").html();
  }

  $(document).bind('click', function(e) {
    var $clicked = $(e.target);
    if (!$clicked.parents().hasClass("dropdown")) $(".dropdown dd ul").slideUp('fast');

  });

  $('.multiSelect input[type="checkbox"]').on('click', function() {
    var title = $(this).closest('.multiSelect').find('input[type="checkbox"]').val(),
      title = $(this).val() + ",";

    if ($(this).is(':checked')) {
      var html = '<span title="' + title + '">' + title + '</span>';
      $('.multiSel').append(html);
      $(".hida").hide();
    } else {
      $('span[title="' + title + '"]').remove();
      var ret = $(".hida");
      $('.dropdown dt a').append(ret);

    }
  });


});
like image 3
colin0117 Avatar answered Oct 13 '22 10:10

colin0117