J Young
J Young

Reputation: 755

Multiple filters on array of objects

I'm currently in the process of porting one of my working, SQL filter based applications so that rather than querying the database every time a filter is changed, it instead filters from one, single, JavaScript array of objects ("the master array").

// console.log(array)

[Object, Object, Object, ...]
    0: Object
        date_created: "2014-12-20"
        product_id: "1"
        product_name: "name"
        type: "0"
        purchased: "1"
    1: Object
        date_created: "2014-12-21"
        product_id: "2"
        product_name: "name2"
        type: "1"
        purchased: "0"
    2: Object
        date_created: "2014-12-21"
        product_id: "3"
        product_name: "name3"
        type: "1"
        purchased: "0"

    ... etc etc

At the moment I have the JavaScript array, and I have a basic filtering system happening whereby I can filter out the results to show only basic items (type == 0), only advanced items (type == 1), or all items. It will then order by the product name, cost, or date added depending on the order by selected.

The way this works is that it loops through the master array, assigns the current object to a variable, and then loops through that specific object. If show only basic is set (true), and key == 'type' && value == 0, then we push that object into a new array. At the end of the master array loop, if the newly array created array is still empty then that means no matches were made. It simply copies the master array across, and then applies some filtering to that array.

My headache, and the bit I cannot wrap my head around, is how do I do multiple filters? An object may be basic AND purchased, but my current algorithm would slot that record in twice. That's when I thought about counting the number of inserts, and then doing an array.splice removing the additional objects, but that failed miserably and returned unwanted results. This was my attempt at that:

function run_filter (type) {
    /*ajax_active = true;
    $('#loading').show().center();*/

    // new empty array
    var new_items = [];

    // items_length refers to the size of the master array (8 objects in total)
    for(var i = 0; i < items_length; i++) {

        // grab the current object
        var object = all_items[i];
        // grab the current size of the new array
        var new_items_length = new_items.length;
        // reset to 0
        var insert_amount = 0;

        // for each key in current object
        for(var key in object) {
            // if show only basic and hide advanced
            if (show_basic && !show_advanced) {
                if (key == 'type' && object[key] == 0) {
                    // push the object onto the new array
                    new_items.push(object);
                    // incrememnt counter by 1
                    insert_amount++;
                } 
            }
            if (show_advanced && !show_basic) {
                if (key == 'type' && object[key] == 1) {
                    new_items.push(object);
                    insert_amount++;
                } 
            }
            // if we want to hide purchased (i.e. omit records where purchased == 1
            if (hide_purchased) {
                if (key == 'purchased' && object[key] == 0) {
                    new_items.push(object);
                    insert_amount++;
                }
            }

            // if increment counter == 2 or greater (i.e. an object has been inserted twice because it is both basic and hasn't been purchased)
            if(insert_amount > 1) {
                // new array length BEFORE objects pushed onto new array (+1 to it so that we don't remove the first instance of the object) ; ... < new array length AFTER objects pushed ; increment on loop
                for(var index = new_items_length + 1; index < new_items_length + insert_amount; index++) {
                    // remove the object from the new array at the current index
                    new_items.splice(index, 1);
                }   
            }
        }
    }
}

On top of that, what if an item is basic, gets pushed into the new array, but the user has also purchased this record and set the filter to hide purchased. It would show that record because it is basic, and ignore the hide purchased filter. I know I could have hundreds of nested if conditions, but that seems inefficient...

Any help??!

Upvotes: 0

Views: 584

Answers (1)

nanndoj
nanndoj

Reputation: 6770

I think you code can be simplified by using Array.filter() which creates a new array with all elements that pass the test implemented by the provided function.:

function run_filter (type) {
    var new_items = all_items.filter(function(obj, index, array) {
        // You can do any filter you want here
        // Just focus on the filter
        return (obj.type == type) && (obj.purchased == "1");
    });

    return new_items;
}

See this Example

Upvotes: 1

Related Questions