Tips for refining search criteria with a combination of checkbox and range slider in Angular 2

In an attempt to refine the results for the array "db," I have implemented three filters: price, duration, and category.

I have experimented with using the filter() method to apply these filters.

You can find the code I have worked on here: https://stackblitz.com/edit/multiple-filters?file=app%2Fapp.component.ts

component.html

<div class="filters">
  <div id="price">
  <h3>Price: {{rangeValues[0] + ' - ' + rangeValues[1]}}</h3>
  <p-slider [(ngModel)]="rangeValues" (click)="handleChange()" [min]="0" 
  [max]="2000" [style]="{'width':'14em'}" [range]="true"></p-slider>
</div>
<hr>
<div id="duration">
    <h3>Duration</h3>
    <li><input type="checkbox" (click)="checkFilter('2 days')"> 2 Days</li>
    <li><input type="checkbox" (click)="checkFilter('6 days')">6 Days</li>
</div>
<hr>
<div id="Theme">
    <h3>Theme</h3>
    <li><input type="checkbox" id="Wild Life" (click)="filterTheme('Wild Life')">Wild Life</li>
    <li><input type="checkbox" id="Romance" (click)="filterTheme('Romance')">Romance</li>
    <li><input type="checkbox" id="Food & Drink" (click)="filterTheme('Food & Drink')">Food & Drink</li>
    <li><input type="checkbox" id="Adventure" (click)="filterTheme('Adventure')">Adventure</li>
 </div>
 <hr>
 </div>

 <div class="results">
    <h3>Results</h3>

    <div *ngFor="let p of package">
    <p>{{p.product_name}}</p>
    </div>
 </div>

component.ts

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit {
 db=[
{
  "id":"1",
  "product_name":"6 Days at Karnataka",
  "price":324,
  "duration":"6 days",
  "category":["Romance"]
},
{
  "id":"5",
  "product_name":"2 Days at Thailand",
  "price":234,
  "duration":"2 days",
  "category":["Romance","Wild Life"]
},
{
  "id":"8",
  "product_name":"2 Days at Delhi",
  "price":1400,
  "duration":"2 days",
  "category": ["Romance","Food & Drink","Adventure"],
}
];
rangeValues: number[] = [0,2000];
package:any;
filterData=[];


ngOnInit(){
  this.packageList();
}

packageList(){
 for(let i = 0; i < this.db.length; i++){
  this.filterData.push(this.db[i]);
  this.package =this.filterData;
 }    
}

handleChange() {
        for(let i = 0; i < this.filterData.length; i++){             
          this.package= this.filterData.filter(item => item.price >=this.rangeValues[0] && item.price <=this.rangeValues[1]);
   }
}

checkFilter(id){ 
    if(id.checked==true){
      for(let i = 0; i < this.filterData.length; i++){
         this.filterData= this.filterData.filter(item => item.duration !== id && item.price >=this.rangeValues[0] && item.price <=this.rangeValues[1]);
          this.package=this.filterData;
      }
    }
    else {
      for(let i = 0; i < this.filterData.length; i++){
          this.filterData= this.filterData.filter(item => item.duration == id && item.price >=this.rangeValues[0] && item.price <=this.rangeValues[1]);
          this.package=this.filterData;
      }
    }
 }


filterTheme(id){
    let b=(<HTMLInputElement>document.getElementById(id));
    if(b.checked==true){
      for(let i = 0; i < this.filterData.length; i++){
        for(let j=0;j< this.filterData[i].category.length; j++){
          if(this.filterData[i].category[j]==id &&  this.filterData[i].price >=this.rangeValues[0] &&  this.filterData[i].price <=this.rangeValues[1]){

            this.package= this.filterData.filter(item => item.category[j]==id && item.price >=this.rangeValues[0] && item.price <=this.rangeValues[1]);
          }
        }
      }
    }else {
      for(let i = 0; i < this.filterData.length; i++){
        for(let j=0;j<this.filterData[i].category.length; j++){
          if(this.filterData[i].category[j]!==id && this.filterData[i].price >=this.rangeValues[0] && this.filterData[i].price <=this.rangeValues[1]){
            this.package = this.filterData.filter(item => item.category[j]!== id && item.price >=this.rangeValues[0] && item.price <=this.rangeValues[1]);

          }
        }
      }
    }

 }

}

My Objective:

  1. price filter: I utilized the range slider to filter price results successfully, but it should also consider the selected duration and category for a comprehensive filter.

  2. Duration filter: To filter by duration, I implemented checkboxes which should work in conjunction with the selected price and category filters.

  3. Category filter: Considering that a product_name can have multiple categories, this filter should refine the results based on the selected category and price combination.

Answer №1

Stop overcomplicating things with unnecessary loops and checks. Simplify your code by creating a single function to handle the task for you.

Step 1: Utilize 3 models

rangeValues: number[] = [0, 2000];
  durations: any = [];
  themes: any = [];

Step 2: Populate these models with user input

  handleChange() {
    this.ApplyFilters();
  }

  checkFilter(id) {
    if (this.durations.some(a => a === id)) {
      this.durations = this.durations.filter(a => a !== id)
    } else {
      this.durations.push(id)
    }
    this.ApplyFilters();
  }


  filterTheme(id) {
    if (this.themes.some(a => a === id)) {
      this.themes = this.themes.filter(a => a !== id)
    } else {
      this.themes.push(id)
    }
    this.ApplyFilters();
  }

Step 3: Implement a common filter function

  ApplyFilters() {
    this.package = this.filterData.filter(item => {
      return (item.price >= this.rangeValues[0] && item.price <= this.rangeValues[1]) && (this.durations.some(b => b === item.duration) || this.durations.length === 0) && (item.category.every(c => this.themes.some(d => d === c)) || this.themes.length === 0)
    });
  }

That's all you need to do.

Check out the demo for reference.

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

Is it possible to achieve real-time two-way data binding in a reactive form by passing values from one formgroup to another formgroup? If so, how

There are 2 FormGroups named orderForm and parcelForm on a page. The parcelForm is generated dynamically within a FormArray. In the parcelForm, there are FormControls like net_weight and gross_weight, while the OrderForm has FormControls such as total_net_ ...

Several different forms are present on a single page, and the goal is to submit all of the data at

Looking for assistance with combining Twitter and Google data entry at once. Here's the code I've developed: Please guide me on how to submit Twitter and Google details together. <html> <head> <script type="text/javascript">< ...

Error encountered using Meteor 1.3 autoform/quickform integration

Having recently transitioned to using Meteor 1.3, I've encountered a few challenges related to debugging due to missing imports or exports in tutorials. This particular issue seems to be in the same vein. I wanted to incorporate the autoform package ...

Execute a sorted operation with proper authorization

Recently, I developed a NextJs dashboard that enables Discord users to connect to their accounts. One of the main features is retrieving the user's guilds and filtering them to include only the ones where the user has either the MANAGE_GUILD permissio ...

Version 4 of Typescript is experiencing crashes when spreading optional arguments

Previously with TypeScript 3.9+, this setup was functioning perfectly: type keys = | 'one' | 'another' | 'yet_another'; type variables = { 'another': { count: number } 'yet_another': { ...

What steps should be taken to effectively integrate Amplify Authenticator, Vue2, and Vite?

Embarked on a fresh Vue2 project with Vite as the build tool. My aim is to enforce user login through Cognito using Amplify. However, when I execute npm run dev, I encounter the following issue: VITE v3.1.3 ready in 405 ms ➜ Local: http://127.0.0 ...

Creating a custom type in Typescript using a function for testing purposes

I have been exploring ways to limit my search capabilities to specific criteria. Let's say I have a model and some data like the following: interface UserModel { _id: string; username: string; party: UserPartyModel; } interface UserParty ...

Tips for effectively utilizing the 'or' operator when working with disparate data types

One of my functions requires an argument that can have one of two different types. If you're interested in TypeScript functions and types, take a look at the official documentation, as well as these Stack Overflow questions: Question 1 and Question 2 ...

Using Selectpicker with Jquery .on('change') results in the change event being triggered twice in a row

While utilizing bootstrap-select selectpicker for <select> lists, I am encountering an issue where the on change event is being triggered twice. Here is an example of my select list: <select class="form-control selectpicker label-picker" ...

I'm encountering an issue where the this.props object is undefined even though I've passed actions to mapDispatchToProps. What could

Summary: The issue I'm facing is that in the LoginForm component, this.props is showing as undefined even though I have passed actions in mapDispatchToProps. I've debugged by setting breakpoints in the connect function and confirmed that the act ...

Combining various JSON objects by nesting them together

I'm in the process of creating an endpoint where I need to combine data from four different tables into one nested object. Each table record is retrieved in JSON format using sequelize - they include information on location, service, staff, and tenant ...

Tips for incorporating if-else statements into your code

How can I incorporate an if statement into my code to print different statements based on different scenarios? For example, I want a statement for when the sum is less than 1, and another for when the sum is greater than 1. I attempted to use examples from ...

What is the best way to manage events within datalist options using Vue.js?

I have a specific requirement where I need to implement a feature in my data list. When a user selects an option from the datalist, I must update other input fields based on that selection. Below is the code snippet for my input field and Datalist: <i ...

Syntax Error: The function `loadReposFromCache(...).error` is not defined in this building

I'm currently attempting to utilize the SyntaxHighlighter v4 plugin, but I'm facing issues with the build process! While following the guidelines provided here, an error popped up: $ ./node_modules/gulp/bin/gulp.js setup-project [10:12:20] Requ ...

What methods are available for identifying non-operational pointer-events?

According to this resource, Opera 12 does not support pointer-events, causing issues with my website. Interestingly, they do support the property in CSS but don't seem to implement it correctly. Modernizr's feature detection doesn't help in ...

Vue Google Tag Manager Error: This file type requires a specific loader to be handled correctly

I have integrated "@gtm-support/vue2-gtm": "^1.0.0" in one of my Vue-2 applications, with Vue versions as below: "vue": "^2.5.2", "vue-cookies": "^1.5.4", "vue-i18n": "^8.0.0", "vue-recaptcha": "^1.1.1", "vue-router": "^3.0.1", "vue-scrollto": "^2.17.1", " ...

Exploring TypeScript: Implementing a runtime data mapping in place of an interface

Take a look at this code snippet that defines two command handlers for a server: import { plainToClass } from "class-transformer"; enum Command { COMMAND_1, COMMAND_2, } class Command1Data { foo1!: string } class Command2Data { foo2!: ...

Nginx and Socket.io: Issues with client-server connection not functioning properly

Hello everyone! I am currently in the process of deploying my application, which utilizes React and NodeJs. However, I have encountered an issue with integrating Socket.io with Nginx. My approach involves editing the Nginx file using the command: sudo ...

Retrieve and save files under a common directory

I have a specific route called payments/transactions that retrieves all relevant data. I'm interested in finding a way to generate a CSV file without the need to create new routes or add query parameters, so that my route appears as payments/transacti ...

Utilizing various directives with distinct scopes for a single element

Is it possible for an element to have multiple directives with their own unique scopes? For example, let's consider a custom directive's child element with the controller's scope along with another directive (such as "ng-class"): <custo ...