Search code examples
angularfirebasegoogle-cloud-firestorelodashangularfire2

How can I filter a firestore collection using lodash _.filter()?


I am trying to filter a collection retrieved from firebase firestore (by the help of angularfire2) . The problem is that I don't get anything into the filtered list.

Here's my code:

companies.component.ts

import { Component, OnInit } from '@angular/core';
import { AngularFirestore, AngularFirestoreCollection } from 'angularfire2/firestore';
import { Observable, BehaviorSubject, combineLatest } from 'rxjs';
import { Company } from '../../shared/models';
import { ReactiveFormsModule, FormGroup, FormBuilder, Validators } from '@angular/forms';
import * as _ from 'lodash';

import { Subject } from 'rxjs';

import { switchMap, map} from 'rxjs/operators';


@Component({
  selector: 'app-companies',
  templateUrl: './companies.component.html',
  styleUrls: ['./companies.component.scss']
})

export class CompaniesComponent implements OnInit {

  filters = {}
  private companiesCollection: AngularFirestoreCollection<Company>;
  companies: any;
  filteredCompanies: any;

  constructor(private readonly afs: AngularFirestore) {
    this.companiesCollection = afs.collection<Company>('companies');
    this.getCompanies().subscribe(() => {
            this.applyFilters();
    });
  }

  ngOnInit() {
  }

  getCompanies() {
    return this.companies = this.afs.collection<Company>('companies').valueChanges();
  }
  /// filter properties that resolve to true
  filterBoolean(property: string, rule: boolean) {
    if (!rule) this.removeFilter(property)
    else {
      this.filters[property] = val => val
      this.applyFilters()
    }
  }

  private applyFilters() {
     this.filteredCompanies = _.filter(this.companies, _.conforms(this.filters) )
  }

companies.component.html

<div class="field">
  <input type="checkbox" (change)="filterBoolean('firstCondition', $event.target.checked)"> True or false 1?
</div>
<div class="field">
  <input type="checkbox" (change)="filterBoolean('secondCondition', $event.target.checked)"> True or false 2?
</div>
<div class="field">
  <input type="checkbox" (change)="filterBoolean('secondCondition', $event.target.checked)"> True or false 3?
</div>


<!-- (WORKING): Displays all the companies names -->
<div *ngFor="let company of companies | async">
  <h6>{{ company.name }}</h6>
</div>

<!-- (NOT WORKING): Displays all the filtered companies -->
<div *ngFor="let filteredCompany of filteredCompanies">
  <h6>{{ filteredCompany.name }}</h6>
</div>

What I'm using:

Angular 6, angularfire2 (v.5), lodash (v.4).

Help:

Am I mismatching the data structure in some way? Anyone that may have a solution to this?

I'm following this tutorial from Jeff Delaney and trying to adapt to firestore instead of realtime database under "Option 1 - Client Side Filtering" in the article.

Any help that can lead me closer to the goal would be much appreciated.

Edit with solution:

DeborahK's answer helped me solve this.

Changed in the constructor to:

this.getCompanies().subscribe(companies => {
        this.companies = companies; // <== Added this line
        this.applyFilters();
});

And the function getCompanies() to:

// Now only returns the retrieved collection    
getCompanies() {
        return this.afs.collection<Company('companies').valueChanges();
}

Solution

  • Where is this.companies set? It looks like you are passing it into the filter, but not setting it anywhere.

    this.filteredCompanies = _.filter(this.companies, _.conforms(this.filters) )
    

    Note in the above code that you are using this.companies as the source for your filtering. If it is not set there won't be any filtered companies.

    Should this code:

    this.getCompanies().subscribe(() => {
            this.applyFilters();
    });
    

    Perhaps be this?

    this.getCompanies().subscribe(companies => {
            this.companies = companies;
            this.applyFilters();
    });