jonasjuss
jonasjuss

Reputation: 173

Custom filtering knockout js observableArray

I have an observableArray with testsuites that I want to filter according to text in a search field. The filtering updates after every key stroke, so I am searching for the most efficient method.

Check out this JS-fiddle for a simplified version of my problem:

http://jsfiddle.net/LkqTU/23180/

Below, you can see a snippet from the fiddle. As of now the filtering takes the entire text in the search field and checks the "Name" field of each testsuite against it.

What I want is to divide the filter text into words and search every field in testsuite for every word in the search field.

I you for example write "user lol" in the search field, I want it to only return the testsuite that contains these words in any field (here two of the testsuites has "user" in the name and one has "lol" in the description).

self.filteredTestsuites = ko.computed(function () {

    // If many white spaces in a row, replace with only one white space
    fText = self.filterText().replace(/\s+/g, ' ');

    // If there is anything in the search box, filter for this
    // As of now this does not divide the filterText and only searches the Name field
    var filteredCollection = ko.utils.arrayFilter(self.testsuites(), function(test) {
        if(fText.length)
            return ( test.name.toUpperCase().indexOf(fText.toUpperCase()) >= 0);
        else
            return 1;
    });

    return filteredCollection;
}, self);

My question is how can I do the searching most efficient? A possible solution is that for every word in the search field, I search every field in the current testsuite. However I would like a more generic solution, where I dont have to specify the fields (e.g. name, description, etc), and I am also unsure about the efficiency of this method.

Suggestions?

Upvotes: 2

Views: 596

Answers (2)

Zack
Zack

Reputation: 2859

I added the DataTables jQuery plugin from https://datatables.net/ to your linked fiddle, using the CDN https://cdn.datatables.net/, and added one line to your javascript, and added the id "theDataTable" to your <table> element, to show what you can do with DataTables.

$('#theDataTable').dataTable();

http://jsfiddle.net/LkqTU/23185/

There is a lot more customization that you can do, but this simple example shows how easy it is to use it to enable searching, sorting, and filtering on all the fields in your table.

Upvotes: 1

Rainer Plumer
Rainer Plumer

Reputation: 3753

A simple solution that ive used before is to merge all searchable keys/text keys into one long searchable text and use that to do all your searching.

A bit simplified version is below.

http://jsfiddle.net/rainerpl/v2krqev5/2/

function ViewModel(){
    var self = this, x, i, suits;

    self.filterText = ko.observable(""); // Text from search field

    // Collection of testsuites
    self.testsuites = ko.observableArray([
        { name: "Register User", description: "Bla bla bla", etc: "Many more fields..." },
        { name: "Delete User", description: "some description", etc: "Many more fields" },
        { name: "Send Money", description: "na-na-na bat man", etc: "Many more fields" }
    ]);
    suits = self.testsuites();

    for ( i = 0; i < suits.length; i++) {
        suits[i]["search_content"] = ">";
        for ( x in suits[i] ) {
            if ( !suits[i].hasOwnProperty(x) || x == "search_content" || typeof suits[i][x] !== "string") {continue;}
            suits[i]["search_content"] += suits[i][x].toUpperCase();
        }
    }
    // Collection of testsuites after going through search filter
    self.filteredTestsuites = ko.computed(function () {
        var reg;
        // If many white spaces in a row, replace with only one white space
        fText = self.filterText().replace(/\s+/gi, '|');
        fText = fText.replace(/\|\s*$/gi, '');
        console.log("regex:", fText);
        reg = new RegExp(fText, "gi");
        // If there is anything in the search box, filter for this
        // As of now this does not divide the filterText and only searches the Name field
        var filteredCollection = ko.utils.arrayFilter(self.testsuites(), function(test) {
            if(fText.length)
                return test.search_content.match(reg);
            else
                return 1;
        });

        return filteredCollection;
    }, self);

}

$(document).ready( function(){
    var vm = new ViewModel();
    ko.applyBindings(vm);
} );

Upvotes: 1

Related Questions