The issues with VUE3 compounding filters are causing unexpected results

Currently, I am attempting to filter search results using multiple filter options. After trying various methods, I have found that when applying only 2 filters, the search works as expected. However, when adding 3 or more filters, it includes additional results that do not meet all of the criteria.

The goal is for the search results to become narrower as more filters are applied.

For a visual demonstration, you can refer to this GIF: https://i.sstatic.net/I6Hhx.jpg

Below is the code I am currently using. It appears quite bloated and complex, especially if more filter options need to be added. If there is a simpler way to achieve this using compounding filters, please share your insights. Thank you!

I am utilizing VUE 3 with the composition API.

 const months = computed(() => {
  return documents.value.filter((plants) =>
    plants.months.includes(month.value)
  );
});
const plantType = computed(() => {
  return documents.value.filter(
    (plants) => plants.plantType == plantT.value
  );
});

const Zone = computed(() => {
  return documents.value.filter((plants) =>
    plants.Zone.includes(getZone.value)
  );
});
const toxicPets = computed(() => {
  return documents.value.filter((plants) =>
    plants.toxicPets.includes(toxic.value)
  );
});

const Combined = computed(() => {
  gettingThree = false;
  return documents.value.filter(
    (plants) =>
      plants.Zone.includes(getZone.value) &&
      plants.months.includes(month.value) &&
      plants.plantType == plantT.value &&
      plants.toxicPets.includes(toxic.value)
  );
});

const Combined2 = computed(() => {
  gettingTwo = true;
  gettingThree = false;
  return documents.value.filter(
    (plants) =>
      (plants.Zone.includes(getZone.value) &&
        plants.months.includes(month.value)) ||
      (plants.Zone.includes(getZone.value) &&
        plants.plantType == plantT.value) ||
      (plants.Zone.includes(getZone.value) &&
        plants.toxicPets.includes(toxic.value)) ||
      (plants.months.includes(month.value) &&
        plants.toxicPets.includes(toxic.value)) ||
      (plants.plantType == plantT.value &&
        plants.toxicPets.includes(toxic.value)) ||
      (plants.plantType == plantT.value &&
        plants.months.includes(month.value))
  );
});

const Combined3 = computed(() => {
  gettingTwo = false;
  gettingThree = true;
  return documents.value.filter(
    (plants) =>
      (plants.Zone.includes(getZone.value) &&
        plants.plantType == plantT.value &&
        plants.months.includes(month.value)) ||
      (plants.Zone.includes(getZone.value) &&
        plants.toxicPets.includes(toxic.value) &&
        plants.plantType == plantT.value) ||
      (plants.Zone.includes(getZone.value) &&
        plants.months.includes(month.value) &&
        plants.toxicPets.includes(toxic.value)) ||
      (plants.plantType == plantT.value &&
        plants.months.includes(month.value) &&
        plants.toxicPets.includes(toxic.value))
  );
});

const searchMatch = computed(() => {
  if (Combined.value.length > 0) {
    console.log("getting 4");
    return Combined.value.filter(
      (plant) =>
        plant.plantName.toLowerCase().indexOf(search.value.toLowerCase()) !=
        -1
    );
  }
  if (Combined3.value.length > 0 && gettingTwo == false) {
    console.log("getting 3");
    return Combined3.value.filter(
      (plant) =>
        plant.plantName.toLowerCase().indexOf(search.value.toLowerCase()) !=
        -1
    );
  }
  if (Combined2.value.length > 0 && gettingThree == false) {
    console.log("getting 2");
    return Combined2.value.filter(
      (plant) =>
        plant.plantName.toLowerCase().indexOf(search.value.toLowerCase()) !=
        -1
    );
  }

  if (
    month.value !== null &&
    getZone.value == null &&
    toxic.value == null &&
    plantT.value == null
  ) {
    return months.value.filter(
      (plant) =>
        plant.plantName.toLowerCase().indexOf(search.value.toLowerCase()) !=
        -1
    );
  }
  if (
    getZone.value !== null &&
    plantT.value == null &&
    month.value == null &&
    toxic.value == null
  ) {
    return Zone.value.filter(
      (plant) =>
        plant.plantName.toLowerCase().indexOf(search.value.toLowerCase()) !=
        -1
    );
  }
  if (
    plantT.value !== null &&
    month.value == null &&
    getZone.value == null &&
    toxic.value == null
  ) {
    return plantType.value.filter(
      (plant) =>
        plant.plantName.toLowerCase().indexOf(search.value.toLowerCase()) !=
        -1
    );
  }
  if (
    toxic.value !== null &&
    plantT.value == null &&
    month.value == null &&
    getZone.value == null
  ) {
    return toxicPets.value.filter(
      (plant) =>
        plant.plantName.toLowerCase().indexOf(search.value.toLowerCase()) !=
        -1
    );
  }

  return documents.value.filter((plant) => {
    return (
      plant.plantName.toLowerCase().indexOf(search.value.toLowerCase()) !=
      -1
    );
  });
});

Answer №1

Wow, I finally cracked the code all by myself!

My solution is now so much simpler compared to what was initially suggested in the original post, and it's producing the results I wanted. Check out the gif to see how it all works now.

Gif - https://i.sstatic.net/x3d4h.jpg

Here's the code I came up with:

// If a variable is null, move on to the next filter. If the variable has a value,
// then filter the results to include that value and move to the next filter.
// Rinse and repeat for each filter.

const Combined = computed(() => {
  return documents.value
    .filter((plants) => {
      return getZone.value == null || plants.Zone.includes(getZone.value); 
    })                                                                    
    .filter((plants) => {
      return month.value == null || plants.months.includes(month.value);
    })
    .filter((plants) => {
      return (
        plantT.value == null || plants.plantType.includes(plantT.value)
      );
    })
    .filter((plants) => {
      return toxic.value == null || plants.toxicPets.includes(toxic.value);
    });
});


// The section below takes the Combined filters property from above and runs it through another computed property to enable user search input using an input field. The search results pass through an array of multiple names per item since plants usually have more than one name. This way, the user can search for different names and still get accurate results.

const searchMatch = computed(() => {                               
  return Combined.value.filter((plant) => {
    let arr_lower = plant.otherNames.map(
      (item) => item.toLowerCase().indexOf(search.value.toLowerCase()) != -1
    ); // This function returns true if the item matches the search results.
    return arr_lower.includes(true); // Here, I'm returning the arr_lower variable if it includes true.
  });
});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Make sure to wait for the loop to complete before moving on to the next line

I am currently leveraging the capabilities of the GitHub API to fetch a list of repositories. Subsequently, I iterate over each repository and initiate another HTTP request to obtain the most recent commit date. How can I orchestrate the iteration process ...

Eliminating unnecessary gaps caused by CSS float properties

I need help figuring out how to eliminate the extra space above 'Smart Filter' in the div id='container_sidebar'. You can view an example of this issue on fiddle http://jsfiddle.net/XHPtc/ It seems that if I remove the float: right pro ...

Creating files using the constructor in Internet Explorer and Safari

Unfortunately, the File() constructor is not supported in IE and Safari. You can check on CanIUse for more information. I'm wondering if there's a workaround for this limitation in Angular/JavaScript? var file = new File(byteArrays, tempfilenam ...

Tips for retrieving data from a database with just one key press

There is a text field that triggers a JavaScript function when a key is pressed. <input type="text" class="text" id="txt_sh_vid" onKeyPress="vhc_record()" maxlength="4"> The function takes the input from the text field and searches for a result in t ...

steps for refreshing value upon click in vue

I am attempting to dynamically reload values when switching tabs without having to refresh the entire page. The values are retrieved from a method. mounted() { this.getOriginalSpace(); }, methods: { getOriginalSpace() { retrieveQuotaSummary(this.va ...

Switch from using getElementById to useRef in React components

There is a requirement to update a functional component that currently uses getElementById to instead utilize the useRef hook. The original code snippet is as follows: import React, { useState, useEffect, useRef } from 'react'; import { createPo ...

VueJS intricate v-if condition

Is there a way to display a button only if two specific conditions are met? I attempted to use v-if with one condition at a time: v-if="editMode" v-if="$can('customersdelete')" When using only one condition at a time, the button displays. This ...

What causes Node's crypto module to generate varying outputs for identical strings?

I'm currently attempting to execute the following program: var crypto = require('crypto'); var a = crypto.createHash('md5').update('89Zr-J591').digest('hex'); var name = '89Zr−J591'; var b = crypto. ...

Calculate the worth of a specific item within an array of objects and save the outcome as a new attribute

I am attempting to calculate the value in each element and then create a new element called "Count". Rule: Count the quantity if the next element has the same "Quantity" value, then add the total to a new element named "Count". I have tried implementing th ...

Is it possible to capture and generate an AxiosPromise inside a function?

I am looking to make a change in a function that currently returns an AxiosPromise. Here is the existing code: example(){ return api.get(url); } The api.get call returns an object of type AxiosPromise<any>. I would like to modify this function so ...

Interacting with jQuery UI Droppable by setting acceptance criteria before submitting a form

My goal is to create a draggable item that can be dropped onto a specific zone. The challenge I'm facing is in displaying a form for inputting information and storing it in a database. If the input is successfully stored, the drop action will be succe ...

Display the keys of a nested array in Vue.js when the structure is unknown

Here is a representation of a dynamic array I have: nodes: [ { n1: "Foods", }, { n4: "Drinks", b7: [ { a2: "Beers", a4: [ ...

How to unselect a radio button in Vue using a button, similar to using vanilla JavaScript

Looking to translate this vanilla JavaScript code into Vue, here's the original: const radio = document.querySelector('#radio'); const boton = document.querySelector('#boton'); boton.addEventListener('click', () => { ...

Issues with Nuxt 3 browser detection and i18n functionality not being operational

Encountering an issue with the Nuxt 3 framework while using i18n (@nuxtjs/i18n: ^8.0.0-rc.5) The i18n functionality is working flawlessly except for the browser language detection. The problem arises when I enable the detectBrowserLanguage feature in the ...

Tips for accessing the most recent embedded document added using the push() method

I'm having difficulty determining the feasibility of this situation. While using the mongoose blog example to illustrate, my specific use case is a bit more complex: var Comments = new Schema({ title : String , body : String , date ...

Obtaining a substantial pdf file using html2pdf

While using html2pdf to generate a PDF of my website, I noticed that the downloaded PDF ends up being 14 pages long. However, after approximately 12 pages, all the colored elements seem to disappear. On mobile screens, this issue occurs even sooner, around ...

What methods can I utilize to showcase the JSON data on my webpage efficiently?

I'm currently working on a script that makes an ajax request. The Cloud appears to be responding with JSON data, but I'm not sure how to display this data on my webpage. Any suggestions? Here you can find a link to view the neatly formatted JSON ...

How to access and retrieve data from a USB flash drive using Javascript

I am looking to print PDF files from a USB flash drive. I have decided to use Mozilla Firefox and the R-kiosk plugin along with the open library PDF.js, but I am facing an issue. How can I read folders and files to create a tree structure without using ...

Firebase Firestore replicates documents, subcollections, and data

Here is a sample structure: .doc Name .colection 1 .doc sub_doc .collection sub_col1 .doc sub_doc .collection 2 .doc sub_doc I want to duplicate this document, including all its sub-collections, to create an ex ...

Why is my jQuery $.ajax success function not providing any results?

When checking the Network tab in Chrome, I noticed that the correct data (action, username, password) is being sent, but the message is not returning to $('#return_login'). Can anyone spot what might be wrong with my code? Below is the jQuery co ...