Angular offers a range of search filters for optimizing search results

The system currently has 3 search fields: 1. Name.... 2. Subject.... 3.Price....
Each of these filters works independently - when searching by name, only results matching that name are displayed; similarly for subject and price.

However, the challenge lies in enabling all filters to work together i.e. finding a person named "BOB" who teaches "English" at a price range of "500-600". How can we establish this connection between multiple filters? https://i.sstatic.net/CV8ji.png

In the component.ts file:
filterSearch is an array containing all user data, while tempFilterSearch is used for displaying it in HTML

searchSubject($event) {
    this.subject = $event.target.value;
    if(this.price == null){
        this.tempFilterSearch = this.filterSearch.filter((res) => {         
            return (                    
                res.subject1.toLocaleLowerCase().match(this.subject.toLocaleLowerCase()) ||
                res.subject2.toLocaleLowerCase().match(this.subject.toLocaleLowerCase()) ||
                res.subject3.toLocaleLowerCase().match(this.subject.toLocaleLowerCase())
                );
            });
    }else if(this.price != null){
        this.tempFilterSearch = this.filterSearch.filter((res)=>{
            console.log(res);
            if((Number(res.price1))>=(Number(this.lowerValue))
                &&(Number(res.price1))<=(Number(this.higherValue)) 
                &&(res.subject1.match(this.subject)) || (res.subject2.match(this.subject))|| (res.subject3.match(this.subject))){
                    return res.subject1 || res.subject2 || res.subject3;
            }
        })
    }

searchName() {  
    this.tempFilterSearch = this.filterSearch.filter((response)=>{
        return response.fullName.toLocaleLowerCase().match(this.name.toLocaleLowerCase());
    })
    
}

searchPrice($event) {
    this.price = $event.target.value.split("-");
    this.lowerValue = this.price[0];
    this.higherValue = this.price[1];
    if (this.subject == null) {
        this.tempFilterSearch = this.filterSearch.filter((res) => {
            if((Number(res.price1))>=(Number(this.lowerValue))&&(Number(res.price1))<=(Number(this.higherValue)))
                return res.price1.toLocaleLowerCase();
            });
    }else if(this.subject != null){
        this.tempFilterSearch = this.filterSearch.filter((res)=>{
            if((Number(res.price1))>=(Number(this.lowerValue))
                &&(Number(res.price1))<=(Number(this.higherValue)) ){
                    return res.price1.toLocaleLowerCase();
            }
        })
    }
}

In the component.html file:

 <div class="tutorWrapper" *ngFor="let element of tempFilterSearch">

I am seeking a solution to enable all filters to work simultaneously.

Answer №1

The sample code provided demonstrates the application of separate filters on a fresh this.filterSearch. This means that each time a new filtering process begins, it resets the previously filtered results and starts afresh.

To optimize this functionality, it is recommended to consolidate all filters into a single logic in order to apply them collectively on the same array, resulting in only one output array. Any changes made to the filters will then trigger a re-iteration starting from the original array, applying all filters sequentially.

As outlined below:

searchSubject($event) {
    this.subject = $event.target.value;
    this.applyFilters();
}

searchName() {  
    //this.name is already assigned 
    this.applyFilters();    
}

searchPrice($event) {
    this.price = $event.target.value.split("-");
    this.lowerValue = this.price[0];
    this.higherValue = this.price[1];
    this.applyFilters();
}

applyFilters() {
    let temp = this.filterSearch;

    // Implementing Subject filter
    if(this.price == null){
        temp = temp.filter((res) => {           
            return (                    
                res.subject1.toLocaleLowerCase().match(this.subject.toLocaleLowerCase()) ||
                res.subject2.toLocaleLowerCase().match(this.subject.toLocaleLowerCase()) ||
                res.subject3.toLocaleLowerCase().match(this.subject.toLocaleLowerCase())
                );
            });
    }else if(this.price != null){
        temp = temp.filter((res)=>{
            if((Number(res.price1))>=(Number(this.lowerValue))
                &&(Number(res.price1)<=(Number(this.higherValue)) 
                &&(res.subject1.match(this.subject)) || (res.subject2.match(this.subject) || (res.subject3.match(this.subject))){
                    return res.subject1 || res.subject2 || res.subject3;
            }
        })
    }

    // Implementing Name filter
    temp = temp.filter((response)=>{
        return response.fullName.toLocaleLowerCase().match(this.name.toLocaleLowerCase());
    })

    // Implementing Price filter
    if (this.subject == null) {
        temp = temp.filter((res) => {
            if((Number(res.price1)>=(Number(this.lowerValue))&&(Number(res.price1)<=(Number(this.higherValue))))
                return res.price1.toLocaleLowerCase();
            });
    }else if(this.subject != null){
        temp = temp.filter((res)=>{
            if((Number(res.price1)>=(Number(this.lowerValue))
                &&(Number(res.price1)<=(Number(this.higherValue)) ){
                    return res.price1.toLocaleLowerCase();
            }
        })
    }

    this.tempFilterSearch = temp;
}

Note: The individual filter functions remain unaltered; this modification simply consolidates and organizes your existing code into a unified function for enhanced efficiency.

Answer №2

I'm responding to this on my phone, so if this answer isn't satisfactory, I'll edit it later on my PC.

My approach would be to create functions for all three possible filters: name, subject, and price. Then, I would have a variable that holds an array of the filtered objects.

For the first filter (name), the function would take the main list array and return all matching elements into the filtered variable.

The subject filter would further filter the filtered variable for subjects, and the output would be reassigned back into the filtered array. The same process applies to the price filter.

Finally, you can iterate through the filtered array using ngfor.

!!EDIT!!

In response to your inquiry about solving the already filtered array issue, here is some pseudo code:

mainArray = [...arrayItems];

filteredArray: Items[];


onFilterButtonPressed(name, subject, price) {

 // You can use an 'if' statement to skip any filter where a value hasn't been provided
  nameFilter();
  subjectFilter();
  priceFilter();
}

nameFilter(name){
  filteredArray = mainArray.filter(item => item.name === name)
}

subjectFilter(subject){
  filteredArray = filteredArray.filter(item => item.subject === subject)
}

priceFilter(price){
  filteredArray = filteredArray.filter(item => item.price === price)
}
<button (click)="onFilterButtonPressed(pass your filter values here)">Click to Filter</button

The above code may seem messy and requires the 'name' variable to exist. To address this, we can use a piping function utilizing reduce() to apply our filters.

// Create a function using reduce, applying each subsequent filter function to the current array
function pipe(...fns) {
  return (arg) => fns.reduce((prev, fn) => fn(prev), arg);
}
// Call the function with our filter functions as arguments
// Our filter functions must filter and return the filtered array, also handling cases where the filter doesn't exist by returning the array unchanged
filteredArray =  pipe(nameFilter, subjectFilter, priceFilter)(MainArray)

I hope this explanation helps!

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

Cloud Firestore query error in Firebase Cloud Function despite data being present in Cloud Firestore

I'm facing an issue with my cloud function. The function is designed to query data from a Cloud Firestore collection, which exists. However, when I call the function from my iOS app, it always goes to the else statement and prints "NOT IN COLLECTION." ...

Creating a TypeScript type that supports a flexible number of generic parameters

I am currently working on creating an emit function that has the capability to accept multiple arguments. In addition, TypeScript will validate the 2nd argument and beyond based on the 1st argument (the event). The code provided below is a starting point, ...

Tips for fixing TypeScript compiler error TS2339: Issue with accessing 'errorValue' property in Angular 5 project

Within a component, I have developed a function to manage errors returned from a Rest Service and determine the corresponding error message to display to the user. This method accepts an error object (custom data structure from the service), navigates to e ...

Guide on utilizing getelementsbytagname for retrieving LI values

As I attempt to locate a specific product on amazon.com, my goal is to extract the ASIN for each item. This particular code snippet runs through various search options and retrieves the price of each product from Amazon one by one. However, in addition to ...

Creating typed props is important when utilizing the Material UI makeStyles function

Currently, I'm in the process of transitioning some of my React components to the latest makeStyles/useStyles hook API from Material UI. As far as I know, I can still accept classes as a prop from parent components by passing the props to useStyles: ...

Is it possible to access the passed arguments in the test description using jest-each?

Utilizing TypeScript and Jest, consider this sample test which can be found at https://jestjs.io/docs/api#testeachtablename-fn-timeout it.each([ { numbers: [1, 2, 3] }, { numbers: [4, 5, 6] } ])('Test case %#: Amount is $numbers.length =&g ...

Restrict dropping items in HTML5 by only allowing the drop if the target div is

I am working on developing a user-friendly visual interface for creating simple graphics. The interface includes 10 image icons and 5 boxes where users can place these icons. Users have the freedom to select which icon they want to display and arrange them ...

Using Props with jQuery in React Components: A Comprehensive Guide

I trust you comprehend this straightforward example. I attempted to modify the background color of my HTML element during initial rendering by managing it in a React Component with a touch of jQuery assistance. Here is the code within my React Component ...

Building an array of objects using a foreach loop

i am struggling to create an array of objects from two input groups, each group consists of 3 inputs with data-side attributes set to left or right every input has a class named "elm" and a data-pos attribute set to a, b, or c <input class="elm-left elm ...

Analyzing past UTC date times results in a peculiar shift in time zones

When I receive various times in UTC from a REST application, I encounter different results. Examples include 2999-01-30T23:00:00.000Z and 1699-12-30T23:00:00.000Z. To display these times on the front end, I use new Date(date) in JavaScript to convert the ...

Exploring the world of child routing in Angular 17

I've been experimenting with child routing in Angular and encountered some confusion. Can someone explain the difference between the following two routing configurations? {path:'products',component:ProductsComponent,children:[{path:'de ...

Error Encountered in Jhipster Application During Initial Launch

Struggling with running a newly generated Jshipster 3 application using gulp serve after successful generation. My setup includes Ubuntu 16.04 and npm 3.9, but I keep encountering an error when attempting to execute gulp serve: check out this screenshot ...

Troubleshooting image loading issues when updating the base URL in an Angular JS project

I am trying to update the base URL for my application. Currently, when I load the application, the URL shows up as http://localhost:4200/#/, but I want it to be http://localhost:4200/carrom/ instead. To accomplish this, I modified the base URL and now th ...

Adapt appearance according to the length of the text

Currently, I have an array that stores multiple strings based on displayed charts. My objective is to find the longest string within this array. So far, this task has been executed without any issues. The code snippet for this process is as follows: var ...

It can be frustrating to have to refresh the page twice in order to see changes when utilizing the revalidate feature in Next

When I make the REST call to fetch data for my page using the code below: // src/app/page.js const Home = async () => { const globalData = await getGlobalData(); return ( <main'> <SomeComponent data={globalData} /> < ...

I'm new to this, but can someone explain why I'm being redirected to the register_db.php page when I click on the register button?

Why when I click the register button, it redirects me to the register_db.php page instead of sending the data to the database and keeping me on the same register.php page? I want the data to be sent to the database without changing the webpage. register.p ...

Click to open a Swipeable Drawer using an onClick event handler in Material UI

Issue Encountered: Currently, in the provided documentation code (https://codesandbox.io/s/cnvp4i?file=/demo.tsx), the drawer opens when the "Open" button is clicked at the top. However, I am looking to have the drawer triggered and opened when it is direc ...

The functionality of the document download button using Express.js and node.js appears to be malfunctioning

For my current project, I am aiming to enable users to effortlessly download a document by simply clicking on a designated button. https://i.sstatic.net/QenII.png Project Outline: https://i.sstatic.net/SxvfV.png public/client.js console.log(&apos ...

Issue with formik onchange event not filling data in Material UI TEXTFIELD component

Greetings! I am currently working on a React project where I am managing the authentication process. I am using Material UI and Formik for validation and handling input changes. However, I encountered an issue with my onchange Formik handler in the TEXTF ...

Is it possible to create a single directive that can handle both Structural and Attribute behaviors?

Trying to develop an Angular Directive that will handle various functionalities based on config input values Dynamically add elements to the DOM based on input values (similar to ngIf) Apply styling to rendered elements Add attribute properties such as d ...