Datatables with column filter dropdowns and multiple checkbox selection

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. =)


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


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);

    }
  });


});