Home > database >  Angular Material Table dataSource won't accept Observable from the app.service.ts
Angular Material Table dataSource won't accept Observable from the app.service.ts

Time:10-07

I am building a simple webshop app in Angular and I want to represent products I get thru the service in an Angular Material Table. I have a Product interface:

export interface Product {
    id: number;
    name: String;
    price: number;
}

I have a products.json in my assets folder. In my service class have getProducts() method that reaches back to the json (in the future possibly to a more distant backend):

private products_url = "/assets/data/products.json";

  public getProducts(): Observable<Product[]> {
    //return this.http.get<Product[]>(`${this.apiServerUrl}/product/all`);
    return this.http.get<Product[]>(this.products_url);
  }

In my component class I have a getProducts() function that reaches out to the service:

  public getProducts(): void {
    this.canteenService.getProducts().subscribe(
      (response: Product[]) => {
        this.products = response;
      },
      (error: HttpErrorResponse) => {
        alert(error.message);
      }
    )
  }

When I want to declare the dataSource for the Material Table in a way that it gets the products thru this getProducts() function in the component, I get an error.

  public dataToDisplay = this.getProducts();;
  public dataSource = new ExampleDataSource(this.dataToDisplay);

The error says: Argument of type 'void' is not assignable to parameter of type 'Product[]'.ts(2345)

How can I fix this?

CodePudding user response:

You need know how work an Observable. An Observable is asyncronous. So you don't get the response else inside subscribe function. So you need

dataSource:MatDataSource<any> //outside you declare the variable

public getProducts(): void {
    this.canteenService.getProducts().subscribe(
      (response: Product[]) => {
        this.products = response;
        //here asign the matDataSource
        this.dataSource = new MatDataSource(this.dataToDisplay);
      },
      (error: HttpErrorResponse) => {
        alert(error.message);
      }
    )
  }

BTW, if you don't need sort or paginate, the data source of a mat-table can be an array, so you can use async pipe

dataSource$=this.canteenService.getProducts() //<--see that is an observable

<table mat-table [dataSource]="dataSource$ |async">
   ...
</table>

NOTE: By defect all the variables of a component you declare are public, so it's unnecessary use public variable:any -you can declare as variable:any-

CodePudding user response:

Your function getProducts() from your component doesn't return anything, you even set the return type as void, also, the naming convention for this particular function is wrong since you are not getting anything

I suggest you do the following:

getProducts$(): Observable<Product[]> {
  return this.canteenService.getProducts();
}
<table [dataSource]="getProducts$()">
 <...>
</table>
  • Related