简体   繁体   中英

How to make an array filter return AND results instead of OR in javascript

Currently my code shows images based on what check boxes a user selects. The array treatments[i] shows everything they check (this OR this OR this). It builds on itself. What I want is an AND situation. Currently if a user clicks on shutters, bathroom, contemporary, the results shows all images that have shutters and all images that are of bathrooms and all images that are contemporary. I want to only show images of contemporary bathrooms that have shutters.

Here is the current code:


function showFilteredImages() {

     var productChoice = [...new Set(productSelect)];
     var roomChoice = [...new Set(roomSelect)];
     var styleChoice = [...new Set(styleSelect)];

        $(".treatment").each(function() {
            $(this).removeClass('filtered');
        });


        for (var i=0; i<treatments.length; i++){
            for (var j=0; j<productChoice.length; j++){
                if (treatments[i].product.indexOf(productChoice[j]) !== -1){
                    treatments[i].$elem.addClass('filtered');
                    break;
                }
            }

            for (var j=0; j<roomChoice.length; j++){
                if (treatments[i].room.indexOf(roomChoice[j]) !== -1){
                    treatments[i].$elem.addClass('filtered');
                    break;
                }         
            }

            for (var j=0; j<styleChoice.length; j++){
                if (treatments[i].style.indexOf(styleChoice[j]) !== -1){
                    treatments[i].$elem.addClass('filtered');
                    break;
                }         
            }
       
        $('.treatment').each(function(index, el){
                if(!$(el).hasClass('filtered')){

                    $(el).hide();
                }   
                else{
                    $(el).show();
                }        
            }); 
    }     

Here is what I've tried:

for (var i=0; i<treatments.length; i++){
            for (var j=0; j<productChoice.length; j++){
                if (treatments[i].product.indexOf(productChoice[j]) !== -1){
                    for (var k=0; j<roomChoice.length; j++){
                        if (treatments[i].room.indexOf(roomChoice[k]) !== -1){
                            for (var l=0; j<styleChoice.length; j++){
                                if (treatments[i].style.indexOf(styleChoice[l]) !== -1){
                                    treatments[i].$elem.addClass('filtered');
                                      
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
        

You can try this

function showFilteredImages() {
    let productChoice = [...new Set(productSelect)];
    let roomChoice = [...new Set(roomSelect)];
    let styleChoice = [...new Set(styleSelect)];

    $(".treatment").each(() => $(this).removeClass("filtered"));

    let choices = [productChoice, roomChoice, styleChoice];

    // the "loop1" is the name of the loop, we need to name it so we can skip an iteration from a nested loop inside it;
    loop1:
    for (let i = 0; i < treatments.length; i++) {
        for (let j = 0; j < choices.length; j++) {
            let choice = choices[j];
            for (let k = 0; k < choice.length; k++) {
                if (treatments[i].product.indexOf(choice[j]) === -1) {
                    // if treatement doesn't have this choice option we just skip it;
                    // here we abort on this iteration of "loop1";
                    // if we didn't name it "loop1", the the code would continue just the loop above this one;
                    continue loop1;
                }
            }
        }
        // if we reached this point, it means the "treatement" has all the choices desired;
        // it has product, room and style;
        // so we add the class filtered to it;
        treatments[i].$elem.addClass("filtered");
    }

    $(".treatment").each(function (index, el) {
        if (!$(el).hasClass("filtered")) {
            $(el).hide();
        } else {
            $(el).show();
        }
    });
}

Explanation

  • First, I grouped the choice groups in one array choices to make easy to loop though them
  • Instead of checking if an element (treatement) is within selection, we check if it isn't, and if it doesn't have one of the critereas we want we skip it.
  • after the choices loop, we add the class filtered to the treatement 's that passed all the criterias.

If treatments is a list of elements, and so are the sets you have, then your code should just iterate treatments once, and check each set to see if it exists therein. You can also show/hide in that single iteration.

Most of the data lacks definition, but I'm going to assume that each Set holds the data in question, so that we don't need to convert it to an Array.

function showFilteredImages() {

    // Let's use these sets
    var productChoice = new Set(productSelect);
    var roomChoice = new Set(roomSelect);
    var styleChoice = new Set(styleSelect);

    // Remove the "filtered" class and hide them all
    $(".treatment").removeClass("filtered").hide();

    // Filter down to the ones meeting the AND condition,
    //   and then add the "filtered" class and show them
    treatments
      .filter(t => 
        t.product.some(item => productChoice.has(item)) &&
        t.room.some(item => roomChoice.has(item))       &&
        t.style.some(item => styleChoice.has(item))
      )
      .forEach(t => t.$elem.addClass("filtered").show())
}

If the only purpose of the "filtered" class was to mark them just so you could re-select them again, it's no longer needed since we're doing all the work immediately.


EDIT: I removed the helper function, since it didn't really make things any shorter or clearer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM