Search code examples
jsonangulararray-filter

Filtering array code isnt rendering the supposed filtered items Angular 9


I have this JSON:

[
    {
    "products": [
        {
            "id": "1",
            "name": "Apple",
            "price": "free",
            "category": "Fruits"
        },
        {
          And so on

And this :

[{
    "categories": [
      {
        "name": "Fruits"
      },
      {
        "name": "vegetables"
      },
      {
        "name": "Meat"
      }
    ]
  }]

The services data, category and product:

export class DataService {

  constructor(@Inject(String) private url: string, private http: HttpClient) { }


  public getAll(): Observable<any> {
    return this.http.get(this.url)
  }

}

export class ProductService extends DataService {

  constructor(http: HttpClient) { 
    super('assets/products.json', http)
  }
}

export class CategoriesService extends DataService {

  constructor(http: HttpClient) { 
    super('assets/categories.json', http)
  }
}

The calls from the home component.ts:

export class HomeComponent implements OnInit {
  categories: Categories[];
  products: Products[]=[];
  filteredProducts: Products[]=[];
  category:string;;
  constructor(
    private categoriesService: CategoryService,
    private productService: ProductService,
    private route: ActivatedRoute) {

    this.categoriesService.getAll().subscribe(categories => {
      this.categories = categories[0]['categories']
    })
    this.productService.getAll().subscribe(p => {
      this.products = p[0]['products']
      console.log(this.products)
    })

    this.route.paramMap.subscribe(params=>{
      this.category = params.get('category');

      this.filteredProducts=(this.categories)? 
      this.products.filter(p=> p.category.toLowerCase()===this.category.toLowerCase()) :
        this.products
      });

  }

And the render Home HTML:

<div class="container">
    <div class="row">
        <div class="col-md-4">
            <mat-list role="list" *ngFor="let c of categories">
                <a role="listitem" routerLink='/home' [queryParams]='{categories: c.name}'>
                    {{c.name}}
                </a>
            </mat-list>
        </div>
        <div class="col-md-8">
            <ul>
                <li *ngFor="let f of filteredProducts">
                        {{f.name}}
                </li>
            </ul>

        </div>
    </div>
</div>

So the issue is that I can render the categories, and as I select them the URL changes. So far, so good. But the implementation of the filter process is not working. I get no errors but I also get no display. Can someone help me figure what I'm missing? (the console.log of this fileterd Rpoducts gives me an array, so im getting the data in the component)


Solution

  • You categories subscription is firing later than your route subscription which falsify your categories? condition inside route subscription. You need to make sure your data is getting filtered after categories data is received from the service.

        export class HomeComponent implements OnInit {
          categories: Categories[];
          products: Products[]=[];
          filteredProducts: Products[]=[];
          category:string;;
          constructor(
            private categoriesService: CategoryService,
            private productService: ProductService,
            private route: ActivatedRoute) {}
    
          ngOnInit() {
              this.route.paramMap.subscribe(params=>{
              this.category = params.get('category');
              forkJoin([this.getCategories(), this.getProducts()]).subscribe(() =>  {
    
                  this.filteredProducts=(this.categories)? 
                  this.products.filter(p=> p.category.toLowerCase()===this.category.toLowerCase()) :
                  this.products; 
              });
    
             })
          }
    
          public getCategories(): Observable<boolean> {
            return this.categoriesService.getAll().pipe(map(categories => {
              this.categories = categories[0]['categories']
              return true;
            }));
          }
          public getProducts(): Observable<boolean> {
            return this.productService.getAll().pipe(map(p => {
              this.products = p[0]['products']
              console.log(this.products)
              return true;
            }));
          }