danielgindi/jquery.dgtable

Search with multiple search fields

sirzento opened this issue · 1 comments

To make this work I only edited a few lines in the code.
The only thing that has changed is that the function responsible for filtering now gets an array of arguments instead of just a single argument.
To search with multiple inputs you don't have to call table.filter({ column: $(temp).attr('Data-column'), keyword: this.value, caseSensitive: false }) in the input text field but table.filter(filterArgs); .
The old method to search still works.

The variable "filterArgs" now only needs to contain all arguments. I implemented this as follows:

filterArgs = [];  //Clear the array.
$.each($("input[id^='filterInput_'"), function () {      //All my searchfields have the id "filterInput_" + column Name e.g. "filterInput_address".
    if (this.value != "") {
     	filterArgs.push({
            column: this.id.replace("filterInput_", ""),     //Here I get the column name. 
            keyword: this.value,
            caseSensitive: false
        });
    }
   lastSearchValue[this.id] = this.value;        //This is only if you are using my code that add a search field in the header of each column.

})

This need to be called everytime if an Input field is changed. This code part is for example in my function thats add a field in the Header of each column and gets bindet on keyup on each Input field.



Here are the changes in your code:

On line 1204 Change the code

p.filterArgs = (typeof args === 'undefined' ? 'undefined' : _typeof(args)) === 'object' && !Array.isArray(args) ? $.extend({}, args) : args;

to

p.filterArgs = (typeof args === 'undefined' ? 'undefined' : _typeof(args)) === 'object';

On line 4301 is the function "RowCollection.prototype.filteredCollection".
Change the function to this:

RowCollection.prototype.filteredCollection = function (filterFunc, args) {
    if (filterFunc && args) {
        for (var rows = new RowCollection({ sortColumn: this.sortColumn }), i = 0, len = this.length, row; i < len; i++) {
            row = this[i];
	    var rowIsFiltered = false;
	    $(args).each(function(){
                if (!filterFunc(row, this)) {
		    rowIsFiltered = true;
		    return false;
		}
	    })
	    if (!rowIsFiltered) {
	        row['__i'] = i;
	        rows.push(row);
	    }
        }
	return rows;
    } else {
        return null;
    }
};

And thats it.
The only drawback is that if you type too fast, the search field will hang for a short time. Maybe you'll find a way to prevent that.


Edit: this drawback is only if I use my search Inputs in the header. This happens because after every keypress the table is rendert again and it cant be rendert multiple times per second if you type too fast. Maybe you can modify your code that the header is only rendert once since it doesnt change if you search.

Edit:
I tried that the header is only renderd once and not after every search but this doenst change it.

Instead, you could just make your filtering function (with setFilter) go over the row and filter by what's relevant. That's why you could pass any args you like.

Untested code:

table.setFilter((row, { filters, caseSensitive }) => {
    let columns = Object.keys(filters).filter(x => filters[x]);
    if (columns.length === 0) return true;

    let keywords = Object.create(null);
    for (let col of columns) {
        keywords[col] = caseSensitive ? filters[col].toString() : filters[col].toString().toLowerCase();
    }
    
    for (let col of columns) {
        let actualVal = row[column];
        if (actualVal == null)
            continue;
        actualVal = actualVal.toString();

        if (!args.caseSensitive)
            actualVal = actualVal.toLowerCase();

        if (actualVal.indexOf(keywords[col]) === -1)
            return false;
    }

    return true;
}


table.filter({ filters: { col1: 'foo', col2: 'bar' }, caseSensitive: true });