How filter javsScript array with multiple parameters

javascript filter array of objects by multiple properties
dynamically filtering an array of objects in javascript
json filter with multiple values
javascript array.filter multiple conditions
filter two array of objects javascript
filter two arrays javascript
filter inside filter javascript
string filter javascript

How to filter data with multiple parameters ? I want to use multiple values in my filter, and combine them with and condition. As you see in image, lets suppose that I type PQR in Organization and Mond in Sales Person meaning that I only want that record in which Organization is PQR and Sales Person is Mond.

i.e to combine these condition, but the problem I'm getting is that If I combine these condition while other inputs (filters) are blank, I doesn't returns any data. My code works perfectly in case of OR condition, in which any of the condition matches. How do I achieve the same type of output by combining the above query Here is my code file and executeFilters() is the function that I'm trying

import { Component, OnInit, ViewChild } from '@angular/core';
import { MatTableDataSource } from '@angular/material/table';
import { Router } from '@angular/router';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { CollectionReportService } from '../../../../../app/services/reportServices/collection-report.service';

@Component({
  selector: 'app-collections-report',
  templateUrl: './collections-report.component.html',
  styleUrls: ['./collections-report.component.scss']
})
export class CollectionsReportComponent implements OnInit {
  dataArrived = false;
  // tslint:disable-next-line: max-line-length
  displayedColumns: string[] = ['date', 'invoice', 'organization', 'customer', 'salesPerson', 'authorizingOfficer', 'item', 'terms', 'ageing', 'quantity', 'price', 'amount', 'dueAmount'];
  footerColumns: string[] = ['amount', 'dueAmount'];
  @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
  @ViewChild(MatSort, { static: true }) sort: MatSort;
  dataSource: any;
  organizationFilter;
  customerFilter;
  salesPersonFilter;
  authorizingOfficerFilter;
  itemFilter;
  constructor(
    private router: Router,
    private collectionReportService: CollectionReportService
  ) { }
  reports = [
    { date: '10 - Oct', invoice: '1009', organization: 'ABC', customer: 'Kevin', salesPerson: 'KEN', authorizingOfficer: 'Ayub', item: 'Jiko', terms: '3', ageing: '4', quantity: '1', price: '3990.00', amount: 3990.00, dueAmount: 1330.00 },
    { date: '10 - Oct', invoice: '1009', organization: 'DEF', customer: 'Lorem', salesPerson: 'Brown', authorizingOfficer: 'Wah', item: 'Okoa', terms: '3', ageing: '4', quantity: '1', price: '3990.00', amount: 3990.00, dueAmount: 1330.00 },
    { date: '10 - Oct', invoice: '1009', organization: 'GHI', customer: 'Ipsum', salesPerson: 'Red', authorizingOfficer: 'IT', item: 'Mishi', terms: '3', ageing: '4', quantity: '1', price: '3990.00', amount: 3990.00, dueAmount: 1330.00 },
    { date: '10 - Oct', invoice: '1009', organization: 'JKL', customer: 'Some', salesPerson: 'Mister', authorizingOfficer: 'Intel', item: 'Chilli', terms: '3', ageing: '4', quantity: '1', price: '3990.00', amount: 3990.00, dueAmount: 1330.00 },
    { date: '10 - Oct', invoice: '1009', organization: 'MNO', customer: 'Frio', salesPerson: 'Kevi', authorizingOfficer: 'Red', item: 'Hitachi', terms: '3', ageing: '4', quantity: '1', price: '3990.00', amount: 3990.00, dueAmount: 1330.00 },
    { date: '10 - Oct', invoice: '1009', organization: 'PQR', customer: 'Litm', salesPerson: 'Bang', authorizingOfficer: 'Mond', item: 'Hari', terms: '3', ageing: '4', quantity: '1', price: '3990.00', amount: 3990.00, dueAmount: 1330.00 },
    { date: '10 - Oct', invoice: '1009', organization: 'STU', customer: 'Nats', salesPerson: 'Elite', authorizingOfficer: 'Amd', item: 'Kara', terms: '3', ageing: '4', quantity: '1', price: '3990.00', amount: 3990.00, dueAmount: 1330.00 },
    { date: '10 - Oct', invoice: '1009', organization: 'VWX', customer: 'Doda', salesPerson: 'Sniper', authorizingOfficer: 'Great', item: 'Yoko', terms: '3', ageing: '4', quantity: '1', price: '3990.00', amount: 3990.00, dueAmount: 1330.00 },
    { date: '10 - Oct', invoice: '1009', organization: 'XYZ', customer: 'Hima', salesPerson: 'Uni', authorizingOfficer: 'Silver', item: 'Hama', terms: '3', ageing: '4', quantity: '1', price: '3990.00', amount: 3990.00, dueAmount: 1330.00 },
    { date: '10 - Oct', invoice: '1009', organization: 'Foo', customer: 'Imk', salesPerson: 'Ten', authorizingOfficer: 'Some', item: 'Spoon', terms: '3', ageing: '4', quantity: '1', price: '3990.00', amount: 3990.00, dueAmount: 1330.00 },
    { date: '10 - Oct', invoice: '1009', organization: 'Bar', customer: 'Tyw', salesPerson: 'Ben', authorizingOfficer: 'Other', item: 'Jiko Okoa', terms: '3', ageing: '4', quantity: '1', price: '3990.00', amount: 3990.00, dueAmount: 1330.00 },
  ];



  ngOnInit(): void {
    this.dataSource = new MatTableDataSource(this.reports);
    this.dataSource.paginator = this.paginator;
    this.dataSource.sort = this.sort;
    this.collectionReportService.getReport().subscribe(resp => console.log('Response of collectionReport: ', resp), error => console.log('Error occured while fetching report: ', error));
  }

  applyFilter(filterValue: string): void {
    this.dataSource.filter = filterValue.trim().toLowerCase();
  }
  getTotalAmount(): number {
    return this.reports.map(r => r.amount).reduce((acc, value) => acc + value, 0);
  }
  getTotalAmountDue(): number {
    return this.reports.map(r => r.dueAmount).reduce((acc, value) => acc + value, 0);
  }
  exportCSV(): void {
    alert('Export function called');
  }

  executeFilters(): void {
    console.log('Organization: ', this.organizationFilter, 'Customer: ', this.customerFilter, 'Sales Person: ',
      this.salesPersonFilter, 'Authorizing Officer: ', this.authorizingOfficerFilter, 'Item: ', this.itemFilter);

    const filteredReport = this.reports.filter(report => report.organization === this.organizationFilter ||
      report.customer === this.customerFilter || report.salesPerson === this.salesPersonFilter || report.item === this.itemFilter ||
      report.authorizingOfficer === this.authorizingOfficerFilter || report.item === this.itemFilter);

    this.dataSource = new MatTableDataSource(filteredReport);
    this.dataSource.paginator = this.paginator;
    this.dataSource.sort = this.sort;

  }
  resetFilters(): void {
    console.log('Filter reset');
    this.organizationFilter = '';
    this.customerFilter = '';
    this.salesPersonFilter = '';
    this.authorizingOfficerFilter = '';
    this.itemFilter = '';


    this.dataSource = new MatTableDataSource(this.reports);
    this.dataSource.paginator = this.paginator;
    this.dataSource.sort = this.sort;
  }

}



Picture for better understanding

You've said you want to use an AND condition but that when you do and not all filters have values, everything is filtered out. I assume you had an && version of your function (in the question you still have ||).

You need to check whether you have a value for the filter before applying it:

const filteredReport = this.reports.filter(report =>
  (!this.organizationFilter || report.organization === this.organizationFilter) &&
  (!this.customerFilter || report.customer === this.customerFilter) &&
  (!this.salesPersonFilter || report.salesPerson === this.salesPersonFilter) &&
  (!this.itemFilter || report.item === this.itemFilter) &&
  (!this.authorizingOfficerFilter || report.authorizingOfficer === this.authorizingOfficerFilter) &&
  (!this.itemFilter || report.item === this.itemFilter)
);

Each criterion in that list is in the form:

(!fieldFilterValue || report.field === fieldFilterValue)

...meaning that the report will match if either A) there isn't a fieldFilterValue (e.g., it's falsy) or B) there is one and the report matches it.

They're then all joined together with && so the overall filter is an AND filter.

Note that the falsy check (!fieldFilterValue) may or may not be appropriate for all your fields, so tweak it if necessary. For instance, if you had a field that was numeric and you wanted to search for reports where that number field had the value 0, the code above wouldn't work. In that case, you could use null as the value for fieldFilterValue when that filter isn't being used, and adjust the code above to:

const filteredReport = this.reports.filter(report =>
  (this.organizationFilter === null || report.organization === this.organizationFilter) &&
  (this.customerFilter === null || report.customer === this.customerFilter) &&
  (this.salesPersonFilter === null || report.salesPerson === this.salesPersonFilter) &&
  (this.itemFilter === null || report.item === this.itemFilter) &&
  (this.authorizingOfficerFilter === null || report.authorizingOfficer === this.authorizingOfficerFilter) &&
  (this.itemFilter === null || report.item === this.itemFilter)
);

Side note: I'd be tempted to avoid having a long list of filters like that, by having a filters object instead of individual organizationFilter, customerFilter, etc. properties:

this.filters = {
  organization: null,
  customer: null,
  salesPerson: null,
  item: null,
  authorizingOfficer: null,
  item: null,
};

and then doing this:

const filteredReport = this.reports.filter(report =>
  Object.entries().every(([key, value]) => value === null || report[key] === value)
);

The downside of that is that you can't search for organizationFilter anymore and find every use of it...

Filters an array of objects with multiple match-criteria. � GitHub, Where the `filters` argument is an object that contains a `key: string` filterArray. test.js Filters an array of objects (one level-depth) with multiple criteria. The filter() method creates an array filled with all array elements that pass a test (provided as a function). Note: filter() does not execute the function for array elements without values. Note: filter() does not change the original array.

You can use multiple filters in stages so you can implement a more complex logic for matching instead of just ===:

const filteredReport = this.reports
    .filter(report => {
        if (!this.organizationFilter) return true // don't filter if blank
        else return report.organization === this.organizationFilter
    })
    .filter(report => {
        if (!this.customerFilter) return true
        else return report.customer === this.customerFilter
    })
    .filter(report => {
        if (!this.salesPerson) return true
        else return report.salesPerson === this.salesPersonFilter
    })
    .filter(report => {
        if (!this.itemFilter) return true
        else return report.item === this.itemFilter
    })
    .filter(report => {
        if (!this.authorizingOfficerFilter) return true
        else return report.authorizingOfficer === this.authorizingOfficerFilter
    });

If you're lazy like me you can even do a little metaprogramming and do this in a loop:

let filteredReport = this.reports.slice();

[
    'organization',
    'customer',
    'salesPerson',
    'item',
    'authorizingOfficer'

].forEach(attr => {
    filteredReport = filteredReport.filter(report => {
        if (!this[attr + 'Filter']) return true
        else return report[attr] === this[attr + 'Filter']
    });
});

Though personally I would at this point rename the filters this.filters.customer etc so that the filter code could be much cleaner:

        if (!this.filters[attr]) return true
        else return report[attr] === this.filters[attr]

JavaScript Array Filter: Filtering Array Elements Based on a Test , JavaScript Array filter() method in detail filter(callback, contextObject); The filter() method creates a new array with all the elements that pass the test implemented by the callback() function. Internally, the filter() method iterates over each element of the array and pass each element to the callback function. Accepting a function as an argument, using .filter() will return a new array with all elements that return true. Product table design Before diving straight into explaining, let's review the

The following code will solve your issue. It would've been better from the beginning if filter were an object instead of a group of strings. First you need to create an interface outside of the component class:

interface Filter{
  organization?: string,
  customer?: string,
  salesPerson?: string,
  item?: string,
  authorizingOfficer?: string
}

Then inside your componenet:

filters: Filter;

executeFilters(): void {
    let filteredReport = this.reports;
    for(filterKey in this.filters){
        filteredReport = filteredReport.filter(report => this.filters[filterKey] === report[filterKey]);
    }

    this.dataSource = new MatTableDataSource(filteredReport);
    this.dataSource.paginator = this.paginator;
    this.dataSource.sort = this.sort;

  }

Using the Array.find Method in JavaScript ← Alligator.io, When you need to find/return multiple values, reach for filter() instead. How to Use Array.find. Using find() is super easy! The only required parameter of this� Introduction to JavaScript array filter() method One of the most common tasks when working with an array is to create a new array that contains a subset of elements of the original array. Suppose you have an array of city objects where each object contains two properties: name and population .

Filtering an array of JSON objects by multiple properties : javascript, How would you do this in basic JS? Array filter? Array map? Array reduce? None of these? I was looping the objects and setting the visible property of the object� If you’re starting in JavaScript, maybe you haven’t heard of .map(), .reduce(), and .filter().For me, it took a while as I had to support Internet Explorer 8 until a couple years ago.

Array.prototype.filter(), Array. prototype. filter � Parameters callback � Return value A new array with the elements that pass the test. � Filtering out all small values � Find all� The parameters, in a function call, are the function's arguments. JavaScript arguments are passed by value: The function only gets to know the values, not the argument's locations. If a function changes an argument's value, it does not change the parameter's original value. Changes to arguments are not visible (reflected) outside the function.

Creating a Multi-Filter Function to Filter Out Multiple Attributes Using , What is .filter() in Javascript? The filter() method creates a new array with all elements that pass the test Accepting a function as an argument, using .filter() will return a new array with all elements that return true . A JavaScript array is initialized with the given elements, except in the case where a single argument is passed to the Array constructor and that argument is a number (see the arrayLength parameter below).

Comments
  • executeFilters uses ||, not &&. I thought you wanted to use an AND condition...?
  • Worked like a charm && thanks for a detailed explanation
  • Unlike the near-equivalent with Java streams, this will result in multiple passes through the data (well, the data that survives earlier passes). (Mind you, it would take hundreds of thousands of reports -- or lots and lots of criteria -- for that to matter.) Separately, it doesn't make sense to call .filter at all if the thing you're filtering on isn't set and so the callback will always return true...
  • @T.J.Crowder This technique is much easier to modularize and easier to allow it to handle complex conditions that may not all be identical. I've used this on live code processing tens of thousands of rows and it barely registers to the user. The processing is still sub one second.
  • Like I said, it takes a lot of records for it to matter. But FWIW, I don't find it simpler than a simple && expression.
  • @T.J.Crowder I didn't say simpler. I said easier to modularize. You can easily imagine how to implement each type of filter as a separate module in a separate file. To do it with && you'd have to rewrite the code to something like this but without individual filters (you can imagine just looping through conditions in a single filter).