2017-11-18 7 views
-1

私はAngular 4アプリを持っています。RxJSで購読した後にオブジェクトのタイプが正しくない

私はAPIのURLでFirebaseデータベースからデータをフェッチするサービスがあります。

import { Product } from './../models/product'; 
import { Observable } from 'rxjs/Observable'; 
import { Injectable } from '@angular/core'; 
import { HttpClient } from '@angular/common/http'; 
import { AppSettings } from '../app-settings'; 

@Injectable() 
export class ProductsService { 

    products = []; 

    constructor(private http: HttpClient) { } 

    getProducts(): Observable<Product[]> { 
    return this.http.get<Product[]>(AppSettings.DB_API_ENDPOINT + '/products.json',); 
    } 
} 

そして、そのデータを表示するコンポーネント:

import { Product } from './../../models/product'; 
import { Component, OnInit, Input } from '@angular/core'; 
import { ProductsService } from '../../services/products.service'; 
import { CategoriesService } from '../../services/categories.service'; 

@Component({ 
    selector: 'products-list', 
    templateUrl: './products-list.component.html', 
    styleUrls: ['./products-list.component.scss'] 
}) 
export class ProductsListComponent implements OnInit { 

    products: Product[]; 
    numberOfProducts: number; 
    page: number; 

    constructor(private productsService: ProductsService, private categoriesService: CategoriesService) { 
    this.page = 1; 
    this.numberOfProducts = 0; 
    this.products = []; 
    } 

    ngOnInit() { 
    this.productsService.getProducts().subscribe(products => { 
     console.log(products[0].getId()); 
     this.products.push(products[0] as Product); 
     this.numberOfProducts = this.products.reduce((prev, el) => { 
     return prev + el.qtyAvailable; 
     }, 0); 
    }); 
    } 

    qtyChange(qty: number) { 
    this.numberOfProducts -= qty; 
    } 

} 

とモデルProduct

export class Product { 
    $key: string; 
    qty: number; 
    isSoldOut: boolean; 

    constructor(
     private id: number, 
     private name: string, 
     private description: string, 
     public qtyAvailable: number, 
     private price: number, 
     private image: string, 
     public category: string 
    ) { 
     this.isSoldOut = false; 
     this.qty = 0; 
    } 

    isAvailable() { 
     return !this.isSoldOut; 
    } 

    getImageUrl() { 
     return '/assets/images/products/' + this.image; 
    } 

    public getId(): number { 
     return this.id; 
    } 

    getPrice() { 
     return this.price; 
    } 

    getDescription() { 
     return this.description; 
    } 

    getName(): string { 
     return this.name; 
    } 
} 

そのコンポーネントの観点から、私はproduct.isAvailable()メソッドを使用しますモデルProduct。コンソールERROR TypeError: _co.product.isAvailable is not a functionにエラーメッセージが表示されます。コンパイル中にproducts[0].idと入力するとエラーメッセージが表示されますが、そのidはプライベートなProductです。このエラー・メッセージのために、プロダクトのリストは表示され、ページ番号が付けられますが、データはありません。

+1

'で、より多くのクリーナーです'**はキャストやコンバージョンを行いません**、コンパイラのヒントに過ぎません。そのクラスのインスタンスが必要な場合は、自分でインスタンスを作成する必要があります。 JSONデータは、プロパティが設定された単なるオブジェクトになります。 – jonrsharpe

+0

はい、わかっています。私はサービス 'subscribe'メソッドでProductオブジェクトを作成しようとしましたが、フィールドがprivateであるというコンパイラエラーが発生しました(つまり、TypeScriptがProductタイプのように扱うことを示しています)、つまり' getId() 'getId()'は関数ではないのでJSコンソールでエラーが発生します(JSは 'Product'型のように扱います)。そして、私は今すぐ立ち往生しています。 – michalk93

+0

あなたが知っていて、試したことがありますか?*その試みの[mcve] **を表示してみませんか?* – jonrsharpe

答えて

1

これをRxjsで整理するより良い方法があります。これはあなたのサービスのmrthod内部のすべてを処理します。参考のため

getProducts(): Observable<Product[]> { 
    return this.http.get<Product[]>(AppSettings.DB_API_ENDPOINT + '/products.json',) 
     .switchMap(res => res); // make the retrieved list an Observable itself 
     .map(product => new Product(product.name // etc)) // map every json object to an instance of your class 
     .toArray(); // when the list is over, the Observable created from the json list will complete, and all of the emitted values will be stored in an array 
} 

は、これらのリンクを参照してください。switchMap operatorを、toArray operator

この方法では、読みやすく、製品としてより反応スタイル

+0

ありがとう!私はこれを以前のように書きました。 'getProducts():Observable {return this.http.get (AppSettings.DB_API_ENDPOINT + '/products.json').map(res=> {res.map(p => new product(p.id、 p.name、p.description、p.qty、p.price、p.image、p.category));}); ' あなたの解決策は読みやすくなります。 – michalk93

-1

私はsubscribeメソッドの内部タイプProductのオブジェクトを作成するには、JavaScriptのオブジェクトの配列構文を使用して私の問題を解決:

this.productsService.getProducts().subscribe(products => { 
     this.products = products.map(p => new Product(p['id'], p['name'], p['description'], p['qtyAvailable'], p['price'],p['image'], p['category'])); 
     this.numberOfProducts = this.products.reduce((prev, el) => { 
     return prev + el.qtyAvailable; 
     }, 0); 
    }); 

しかし、それでもまだ、私はそれが冗長であると思います。 Angularは自動的にタイプをProduct[]に変換する必要がありますか?

+1

1.入力はTypeScript機能であり、角度固有ではありません。 2.いいえ、そうすべきではありません。 – jonrsharpe

+0

お返事ありがとうございます@jonrsharpe。私は次の質問があります。 'this.productsService.getProducts()。subscribe(....) 'を使うたびにコードを繰り返さないように、' ProductService'の 'getProducts'メソッドの中で' Product [] 'のこの作成を行うことは可能ですか?私はコードを非同期のままにして、 'ProductService'でのみ変換を行いたいと思います。 – michalk93

+1

はい、もちろんです。私はあなたがそれについて考える時間を過ごすことをお勧めします。 – jonrsharpe

関連する問題