1
votes

I am going through a video course and I got this error. In products.component.ts I get the following error on the console. I am having trouble with observables.

ERROR in src/app/products/products.component.ts(30,18): error TS2345: Argument of type '(products: Product[]) => Observable' is not assignable to parameter of type '(value: { key: string; }[], index: number) => ObservableInput'. Types of parameters 'products' and 'value' are incompatible. Type '{ key: string; }[]' is not assignable to type 'Product[]'. Type '{ key: string; }' is missing the following properties from type 'Product': $key, title, price, category, imageUrl

here is products.component.ts

import { ShoppingCartService } from './../shopping-cart.service';
import { Product } from './../models/product';
import { ActivatedRoute } from '@angular/router';
import { ProductService } from './../product.service';
import { Component, OnInit, OnDestroy } from '@angular/core';
import 'rxjs/add/operator/switchMap';
import { Subscription } from 'rxjs';


@Component({
  selector: 'app-products',
  templateUrl: './products.component.html',
  styleUrls: ['./products.component.css']
})
export class ProductsComponent implements OnInit, OnDestroy {
  products: Product[] = [];
  filteredProducts: Product[] = [];
  category: string;
  cart: any;
  subscription: Subscription;

  constructor(
    route: ActivatedRoute,
    productService: ProductService,
    private shoppingCartService: ShoppingCartService) {


    productService
      .getAll()
      .switchMap((products: Product[]) => {
        this.products = products;
        return route.queryParamMap;
      })
      .subscribe(params => {
        this.category = params.get('category');

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

  async ngOnInit(){
   this.subscription = (await 
   this.shoppingCartService.getCart()).valueChanges().subscribe(cart => 
   this.cart);
  }

  ngOnDestroy(){
    this.subscription.unsubscribe();
  }
}

here is product.ts

export interface Product {
    $key: string;
    title: string;
    price: number;
    category: string;
    imageUrl: string;
}

here is product.service.ts

import { AngularFireDatabase } from '@angular/fire/database';
import { Injectable } from '@angular/core';
import { map } from 'rxjs/operators';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class ProductService {
  constructor(private db: AngularFireDatabase) { }

  create(product) { 
    return this.db.list('/products').push(product);
  }

  getAll(){
    return this.db.list('/products').snapshotChanges().pipe(map(categories 
=> {
      return categories.map(c => ({ key: c.payload.key, ...c.payload.val() 
}));
    }));
  }

  get(productId){
    return this.db.object('/products/' + productId).valueChanges();
  }

  update(productId, product){
    return this.db.object('/products/' + productId).update(product);
  }

  delete(productId){
    return this.db.object('/products/' + productId ).remove();
  }
}
1

1 Answers

1
votes

This parts looks like it uses old version of rxjs (new version operators need to be in pipe method) also not best logic for handling observables

productService
  .getAll()
  .switchMap((products: Product[]) => {
    this.products = products; // this isnt particular good solution
    return route.queryParamMap;
  })
...

update it to

import { combineLatest } from 'rxjs'
...
combineLatest(
  productService.getAll(),
  route.queryParamMap,
).subscribe(([products, params]) => {
  ...
})