Type 'Observable' is not assignable t

2020-03-01 05:29发布

问题:

I am pretty new in Angular2/TypeScript so please excuse me if I am doing some stupid mistake. What I am trying to do is from Select drop down I am populating the data using service which is returning me a JSON array.

Here is my code:

product-maintenance.component.ts

import { Component, OnInit} from '@angular/core';
import { ProductMaintenanceService } from '../../_services/product-maintenance.service';
import { ModuleConst } from '../../../data/const';
import { Product } from './product-types';
import { Products } from './products';

@Component({
  selector: 'app-product-maintenance',
  templateUrl: './product-maintenance.component.html',
  styleUrls: ['./product-maintenance.component.css']
})

export class ProductMaintenanceComponent implements OnInit {
 selectedProduct: Product = new Product(0, 'Insurance');
 products: Product[];
 productList: Products[];

 constructor( private productService: ProductMaintenanceService ) {

 }

    ngOnInit() {
      // Dropdown list
      this.products = this.productService.getProductTypeList();
    }
    // Populate data using onSelect method
    onSelect(typeid) {
      this.productList = this.productService.getProducts()
        .filter((item)=>item.ptypeid == typeid);
    }
}

product-type.ts (used for to populate drop down list):

export class Product {
  constructor(
    public ptypeid: number,
    public name: string
  ) { }
}

products.ts (used for to populate data from service):

export class Products {
  constructor(
      public id: number,
      public ptypeid: number,
      public name: string,
      public currency: string,
      public state: string,
      public riskRating: number,
      public clientSegment: string,
      public aiStatus: string,
      public premiumType: string,
      public tenure: number
  ) { }
}

product-maintenance.service.ts:

import { Injectable, Inject } from '@angular/core';
import { Http, Headers, RequestOptions, Response } from '@angular/http';
import { Observable } from 'rxjs/Rx';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/filter';
import { APP_CONFIG, IAppConfig } from '../app.config';
import { Products } from './products';
import { Product } from './product-types';

@Injectable()
export class ProductMaintenanceService {
    result: Array<Object>;
    constructor(
        @Inject(APP_CONFIG) private config: IAppConfig,
        private http: Http
      ) { }

    private productURL = 'data/productList.json';

    // Get product list
    getProducts() : Observable<any> {
     // ...using get request
     return this.http.get(this.productURL)
        // ...and calling .json() on the response to return data
        .map((response: Response) => {
          console.log(response);
          return response.json();
        });
     }


     getProductTypeList() {
       return [
         new Product(1, 'Unit Trust'),
         new Product(2, 'Insurance'),
         new Product(3, 'Structured Deposit'),
         new Product(4, 'Bonds'),
         new Product(5, 'DCI'),
         new Product(6, 'SP')
       ];
     }
}

product-maintenance.component.html:

<table>
<tr *ngFor="let item of productList">
                <td>{{ item.id }}</td>
                <td>{{ item.name }}</td>
                <td>{{ item.currency }}</td>
                <td>{{ item.state }}</td>
                <td>{{ item.riskRating }}</td>
                <td>{{ item.clientSegment }}</td>
                <td>{{ item.aiStatus }}</td>
                <td>{{ item.premiumType }}</td>
                <td>{{ item.tenure }}</td>
            </tr>
</table>

productList.json:

[
      {
        "ptypeid": 1,
        "id": 1,
        "name": "Unit Trust 1",
        "currency": "SGD",
        "state": "Active",
        "riskRating": 1,
        "clientSegment": "Retail/Premier",
        "aiStatus": "No",
        "premiumType": "Regular Premium",
        "tenure": 5
      },
      {
        "ptypeid": 2,
        "id": 2,
        "name": "Unit Trust 2",
        "currency": "SGD",
        "state": "Active",
        "riskRating": 3,
        "clientSegment": "Retail/Premier",
        "aiStatus": "No",
        "premiumType": "Single/Lumpsum Premium",
        "tenure": 10
      }
]

If I define my getProducts() as getProductTypeList() then it's perfectly populating the data in my view (Where if I select Unit trust from the drop down then it should populate relevant data). But if I use as api url instead it's giving me below error:

Type 'Observable<any>' is not assignable to type 'Products[]'. Property 'length' is missing in type 'Observable<any>'

I don't understand how to resolve this error. Can anyone please help me in this. Thanks in advance.

回答1:

productList should be Product[] not Observable<any>. So assign productList value from getProducts subscribe method, where you will retrieve array of Product

onSelect(typeid) {
  this.productService.getProducts()
    .filter((item)=>item.ptypeid == typeid)
    .subscribe((products) => {
       this.productList = products;
    });
}


回答2:

Change your method getProducts method to

getProducts() : Observable<any> {
     // ...using get request
     let response = this.http.get(this.productURL)
        // ...and calling .json() on the response to return data
        .map((response: Response) => response.json());
    return response;
 }


回答3:

A couple of problems, first I noticed you are using a relative url for your get-request. That is not going to work. You need to have the correct url, meaning something that starts with http://.. even if your api is on localhost you need to provide the complete url.

Secondly, the get request is okay, but your call in your component should look like this:

this.productService.getProducts()
  .subscribe(data => {
   this.productList = data})

Since you are doing a map in your request, you also need to subscribe to that, otherwise you won't get any results!

Worth mentioning is also, since this is an async operation, you might want to include a ngIf in your table, so that your app won't throw an error in case view is rendered before data has arrived, so just do this:

<table *ngIf="productList">

This should clear things up!

Alternatively, if you do not want to subscribe, you can do as you previously did:

this.products = this.productService.getProductTypeList();

but then you have to use the async pipe in the view:

<tr *ngFor="let item of productList | async">

In this case the async-pipe does the subscription for you :)