0

I'm following this tutorial and I'm stuck in this feature where I have to display a filtered array (object coming from firebase) when clicking an anchor. I followed all the implementation steps but I'm missing something...The code:

HTML:

<div class="row">
    <div class="col-3">
        <div class="list-group">
            <a
            *ngFor="let c of categories$ | async"
            routerLink="/"
            [queryParams]="{category: c.$key}"
            class="list-group-item list-group-item-action"
            [class.active]="category===c.$key">
            {{c.name}}
            </a>
        </div>
    </div>


<div class="col">
<div class="row">
    <ng-container *ngFor="let p of filteredProducts; let i =index">
        <div class="col">

            <div class="card" style="width: 15rem;">
                <img src="{{p.imageURL}}">
                <div class="card-body">
                    <h5 class="card-title">{{p.title}}</h5>
                    <p class="card-text">{{p.price | currency: 'EUR': true}}</p>
                    <a href="#" class="btn btn-primary">Add to cart</a>
                </div>
            </div>

        </div>
        <div></div>
    </ng-container>

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

TS class:

products:Product[]=[];
  filteredProducts: Product[]=[];
  category: string;
  categories$;
  constructor(
    private productService: ProductService, 
    private categoryService: CategoryService,
    private route: ActivatedRoute) { 
    this.categories$=this.categoryService.getCategories();
    this.productService.getAll().subscribe(products =>this.products=products)

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

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

  }

The service retrives data correcly, but when I log the filtered array, I get nothing...Can someone give me a hand?

EDIT: enter image description here

2
  • You should nest the subscribes, They are both async calls. There is no guarantee once you hit "this.route.queryParamMap..." the previous getAll() method has finished. It's likely whats happening. You are trying to filter an empty array Commented Jul 31, 2019 at 19:50
  • @sinanspd you should never nest subscribes Commented Jul 31, 2019 at 19:51

1 Answer 1

1

your attempting to set your array before you retrieve the products. subscribe is an asynchronous operation so it doesn't execute in the order it's started, but rather in the order the results arrive, and queryParams is a type of observable that emits immediately, so that subscribe is executing BEFORE the products arrive, instead, use observable combineLatest and the map operator and the async pipe:

filteredProducts$: Observable<Product[]>;

....

const category$ = this.route.queryParamMap.pipe(map(params => params.get('category')));
this.filteredProducts$ = combineLatest(this.productService.getAll(), // combine the streams
                                       category$)
                           .pipe(
                             tap(([products, category])=> console.log(products, category)), // this is how you log in a stream
                             map(([products, category]) => // you'll have the latest value from both
                               (category) ? // run your filter
                                 products.filter(p => p.category.toLowerCase() === category.toLowerCase()) :
                                 products),
                             tap(filteredProducts => console.log(filteredProducts)) // this is how you log in a stream
                           );

then in your template just use the async pipe like you did with categories$

<ng-container *ngFor="let p of filteredProducts$ | async; let i =index">

an Observable is JUST a definition of how to handle a stream of data. logging things outside of that stream will not show you the values inside of that stream. the tap operator exists to allow you to log things inside of the stream

Sign up to request clarification or add additional context in comments.

6 Comments

I understand your logic but as is the output is the same and I can't even read the params in the console, it stays undefined..
it depends where you're logging.... it's jsut a stream definition until it's executed
added a logging line for you
the logs of the code you provided show an empty array of filter...I don't get this because even assuring the object comes first than the reading of params, the filter arry remains empty
i looked at your edits... it looks like the "categories" are in all lower case but the category field on your products has it's first letter upper case.... this would not yield an exact match
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.