Skip to content

Instantly share code, notes, and snippets.

@sglessard
Created March 10, 2014 19:12
Show Gist options
  • Save sglessard/9472131 to your computer and use it in GitHub Desktop.
Save sglessard/9472131 to your computer and use it in GitHub Desktop.
jquery.filtertable.js modification to not reset when clicking on keyword input https://github.com/sglessard/jQuery.FilterTable/blob/master/jquery.filtertable.js
/**
* jquery.filterTable
*
* This plugin will add a search filter to tables. When typing in the filter,
* any rows that do not contain the filter will be hidden.
*
* Utilizes bindWithDelay() if available. https://github.com/bgrins/bindWithDelay
*
* @version v1.5
* @author Sunny Walker, swalker@hawaii.edu
*/
(function($) {
var jversion = $.fn.jquery.split('.'), jmajor = parseFloat(jversion[0]), jminor = parseFloat(jversion[1]);
if (jmajor<2 && jminor<8) { // build the pseudo selector for jQuery < 1.8
$.expr[':'].filterTableFind = function(a, i, m) { // build the case insensitive filtering functionality as a pseudo-selector expression
return $(a).text().toUpperCase().indexOf(m[3].toUpperCase())>=0;
};
} else { // build the pseudo selector for jQuery >= 1.8
$.expr[':'].filterTableFind = jQuery.expr.createPseudo(function(arg) {
return function(el) {
return $(el).text().toUpperCase().indexOf(arg.toUpperCase())>=0;
};
});
}
$.fn.filterTable = function(options) { // define the filterTable plugin
var defaults = { // start off with some default settings
callback: null, // callback function: function(term, table){}
containerClass: 'filter-table', // class to apply to the container
containerTag: 'p', // tag name of the container
hideTFootOnFilter: false, // if true, the table's tfoot(s) will be hidden when the table is filtered
highlightClass: 'alt', // class applied to cells containing the filter term
inputName: '', // name of filter input field
inputType: 'search', // tag name of the filter input tag
label: 'Filter:', // text to precede the filter input tag
minRows: 8, // don't show the filter on tables with less than this number of rows
placeholder: 'search this table', // HTML5 placeholder text for the filter field
quickList: [], // list of phrases to quick fill the search
quickListClass: 'quick', // class of each quick list item
quickListGroupTag: '', // tag surrounding quick list items (e.g., ul)
quickListTag: 'a', // tag type of each quick list item (e.g., a or li)
visibleClass: 'visible', // class applied to visible rows
filterElementIds: [] // list of filter element ids (can be input or select elements) Ex.: ['#my-input-filter','#my-select-filter'] SELECT element can be linked to a table column by adding the element id as a <th> class.
},
hsc = function(text) { // mimic PHP's htmlspecialchars() function
return text.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
},
settings = $.extend({}, defaults, options); // merge the user's settings into the defaults
var doFiltering = function(table, q, classRow) { // handle the actual table filtering
var tbody=table.find('tbody'); // cache the tbody element
if (q==='') { // if the filtering query is blank
tbody.find('tr').show().addClass(settings.visibleClass); // show all rows
tbody.find('td').removeClass(settings.highlightClass); // remove the row highlight from all cells
if (settings.hideTFootOnFilter) { // show footer if the setting was specified
table.find('tfoot').show();
}
} else { // if the filter query is not blank
tbody.find('tr').hide().removeClass(settings.visibleClass); // hide all rows, assuming none were found
if (settings.hideTFootOnFilter) { // hide footer if the setting was specified
table.find('tfoot').hide();
}
var table_td_selector = 'td';
if (typeof classRow != 'undefined' && $('th.'+classRow).length > 0) { // if a filterelementid is linked to a column (<th>)
var th_index = $('th.'+classRow).get(0).cellIndex+1;
table_td_selector += ':nth-child('+th_index+')';
}
tbody.find('td').removeClass(settings.highlightClass); // remove highlights
tbody.find(table_td_selector).filter(':filterTableFind("'+q.replace(/(['"])/g,'\\$1')+'")').addClass(settings.highlightClass).closest('tr').show().addClass(settings.visibleClass); // highlight (class=alt) only the cells that match the query and show their rows
}
if (settings.callback) { // call the callback function
settings.callback(q, table);
}
}; // doFiltering()
var doReseting = function(activeId) {
$.each(settings.filterElementIds, function(_index,_elementId) {
if (_elementId != activeId) $(_elementId).val('');
});
};
return this.each(function() {
var t = $(this), // cache the table
tbody = t.find('tbody'), // cache the tbody
container = null, // placeholder for the filter field container DOM node
quicks = null, // placeholder for the quick list items
filter = null; // placeholder for the field field DOM node
if (t[0].nodeName==='TABLE' && tbody.length>0 && (settings.minRows===0 || (settings.minRows>0 && tbody.find('tr').length>settings.minRows)) && !t.prev().hasClass(settings.containerClass)) { // only if object is a table and there's a tbody and at least minRows trs and hasn't already had a filter added
container = $('<'+settings.containerTag+' />'); // build the container tag for the filter field
if (settings.containerClass!=='') { // add any classes that need to be added
container.addClass(settings.containerClass);
}
container.prepend(settings.label+' '); // add the label for the filter field
if (settings.filterElementIds.length < 1) {
filter = $('<input type="'+settings.inputType+'" placeholder="'+settings.placeholder+'" name="'+settings.inputName+'" id="jft-'+settings.inputName+'" />'); // build the filter field
settings.filterElementIds = ['#jft-'+settings.inputName];
container.append(filter); // add the filter field to the container
t.before(container); // add the filter field and quick list container to just before the table
}
$.each(settings.filterElementIds,function(index,elementId) {
filter = $(elementId) // get the filter field
if (filter.length < 1) return true; // continue if not exist
// Input text
if (filter.get(0).tagName == 'INPUT') {
if ($.fn.bindWithDelay) { // does bindWithDelay() exist?
filter.bindWithDelay('keyup', function() { // bind doFiltering() to keyup (delayed)
doReseting(elementId);
doFiltering(t, $(this).val());
}, 200);
} else { // just bind to onKeyUp
filter.bind('keyup', function() { // bind doFiltering() to keyup
doReseting(elementId);
doFiltering(t, $(this).val());
});
} // keyup binding block
// Select object
} else if (filter.get(0).tagName == 'SELECT') {
filter.change(function() { // bind doFiltering() to select
doReseting(elementId);
doFiltering(t, $(this).val(),$(this).attr('id'));
});
}
});
if (settings.quickList.length>0) { // are there any quick list items to add?
quicks = settings.quickListGroupTag ? $('<'+settings.quickListGroupTag+' />') : container;
$.each(settings.quickList, function(index, value) { // for each quick list item...
var q = $('<'+settings.quickListTag+' class="'+settings.quickListClass+'" />'); // build the quick list item link
q.text(hsc(value)); // add the item's text
if (q[0].nodeName==='A') {
q.attr('href', '#'); // add a (worthless) href to the item if it's an anchor tag so that it gets the browser's link treatment
}
q.bind('click', function(e) { // bind the click event to it
e.preventDefault(); // stop the normal anchor tag behavior from happening
filter.val(value).focus().trigger('click'); // send the quick list value over to the filter field and trigger the event
});
quicks.append(q); // add the quick list link to the quick list groups container
}); // each quick list item
if (quicks!==container) {
container.append(quicks); // add the quick list groups container to the DOM if it isn't already there
}
} // if quick list items
} // if the functionality should be added
}); // return this.each
}; // $.fn.filterTable
})(jQuery);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment