Home > Back-end >  Filter JSON in Angular
Filter JSON in Angular

Time:08-14

I have the below JSON file which is part of my Angular project

[
  {
    "name": "Product A",
    "slug": "product-a",
    "short_description": "some description"
  },
  {
    "name": "Product B",
    "slug": "product-b",
    "short_description": "some description 2"
  }
]

In my service, I am doing a get request to get the above json

getProducts() {
  return this.http.get('../../../assets/products.json');
}

Now in my products listing page, I am doing a request to get the list of products and looping over them to render them on page. This is working fine. Below is what I'm doing:

products = <any>[];

ngOnInit(): void {
    this.products = this.productsService.getProducts();
}

My issue is that once the user clicks on one of the products, I'm redirecting him to the product details page and I need to load the product details. The way I was tackling it was to try and do another request to get the products and trying to filter them to load the needed product. Below is what I was trying, which is returning and array with the needed object. However I just need the object to be able to use it in the template.

this.route.params.subscribe((params) => {
  const productSlug = params['product-name'];

  this.productService
  .getProducts()
  .subscribe((data: any) => {
    this.product = data.filter((item: { slug: any; }) => item.slug === productSlug);
  })

Can someone tell me how I can get the object directly, rather than an object inside an array? I am new to Angular and for sure there should be a more elegant solution to do this rather than doing the same request twice and then filter. So any suggestions on how to improve this would be more than welcome.

CodePudding user response:

The product service should store the retrieved products. Look up Angular RxJS observable services - generally they will be set up with a BehaviorSubject. The service can have an additional method to return a product by id (or slug in your case)

An Angular resolver would be useful here too, to make sure all the products are fetched before the page loads - that's a common approach

CodePudding user response:

Update your service to store the list of products so you would be able to run normal array functions on them.

Your service should be something like this:

import {Observalbe, BehaviorSubject, Of} from 'rxjs';
import {pipe, tap} from 'rxjs/operators';

@Injectable()
class ProductService {
 private _products = [];
 private product$ = new BehaviorSubject(_products);

 getProducts(): Observable(IProduct[]) {
  // here you can check if the `_products` already exist,
  // so return this.product$.asObservable
  // Or you can use `switchMap` to return the `protuct$`
  // We used tap, to store products every time we fetch it.
  return this.http.get('../../../assets/products.json')
              .pipe(tap(products => this._products = products));
 }

 getProduct(id: string): Observalbe(IProduct) {
  const product = this._products.find(product => product.id === id);
  return of(product);
 }
}
  • Related