潜在的“重复”问题没有回答我的问题 - 我可能认为我对Observables的使用与示例不同,正如我所指出的,我尝试使用share()失败。
我有一个看起来像这样的服务:
import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Card } from '../../card';
import { Observable } from 'rxjs/Rx';
@Injectable()
export class CardService {
private privateUrl = 'http://localhost:3335/cardname/';
constructor (private http: Http) {}
public getDetailedInfo(card): Observable<Card> {
return this.http.get(`${this.privateUrl}${card.name}`)
.map(this.extractData);
}
private extractData(res: Response) {
let body = res.json();
return new Card(body.data.name, body.data.card_type, body.data.text);
}
}
使用它的组件看起来像:
import { Component, OnInit } from '@angular/core';
import { Card } from '../../card';
import { CardService } from '../../services/card/card.service';
import { CARDNAMES } from '../../cards';
@Component({
selector: 'main',
styles: [require('./main.component.scss').toString()],
template: require('./main.component.html'),
providers: [CardService]
})
export class MainComponent implements OnInit {
mode = 'Observable';
title = 'YuGiOh Deck Browser';
cardnames = CARDNAMES;
card: Card;
selectedCard: Card;
dataStore: Array<any> = [];
constructor(private cardService: CardService) { }
ngOnInit() {
for (let prop in this.cardnames) {
this.getDetailedInfo(this.cardnames[prop]);
}
}
onSelect(card: Card): void {
this.getDetailedInfo(card);
}
getDetailedInfo(card) {
this.cardService.getDetailedInfo(card)
.subscribe((card: Card) => {
this.card = this.selectedCard = card;
this.dataStore.push(card);
});
}
}
我的模板是:
<div *ngIf="card">
<h2>{{card.name}}</h2>
<div class="card-type">{{card?.card_type}}</div>
<div class="card-description">{{card?.text}}</div>
</div>
我的卡片看起来像这样:
export class Card {
response:string;
constructor(
public name: string,
public card_type: string,
public text: string
) { }
}
我在阅读this和that之后尝试使用share()
,cache()
,publishReplay(1).refCount()
,但似乎没有什么可以阻止点击时获取HTTP请求处理程序被调用。
我误解了这些方法实际上做了什么吗?
我还尝试在this first answer in this question之后将数据保存在内存中的对象数组(代码示例跟随)中,这些对象部分有效,但在单击并触发onSelect事件时失败。
import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Card } from '../../card';
import { Observable } from 'rxjs/Rx';
@Injectable()
export class CardService {
private dataStore: Array<any> = [];
private observable: Observable<Card>;
private privateUrl = 'http://localhost:3335/cardname/';
constructor (private http: Http) {}
public getDetailedInfo(card): Observable<any> {
if (this.dataStore.length > 0) {
this.dataStore.forEach((value, index) => {
return new Card(
this.dataStore[index].data.name,
this.dataStore[index].data.card_type,
this.dataStore[index].data.text
)
});
} else if (this.observable) {
return this.observable;
} else {
return this.http.get(`${this.privateUrl}${card.name}`)
.map(
(res) => {
let body = res.json();
this.dataStore.push(body);
return new Card(body.data.name, body.data.card_type, body.data.text);
}
);
}
}
}
VM99537:93 EXCEPTION: Error in ./MainComponent class MainComponent - inline template:4:8
2016-09-11 21:04:03.241 zone.js?c625:269 Uncaught EXCEPTION: Error in ./MainComponent class MainComponent - inline template:4:8
ORIGINAL EXCEPTION: TypeError: Cannot read property 'subscribe' of undefined
ORIGINAL STACKTRACE:
TypeError: Cannot read property 'subscribe' of undefined
at MainComponent.getDetailedInfo (eval at <anonymous> (http://localhost:5000/bundle.js:965:2), <anonymous>:32:13)
at MainComponent.onSelect (eval at <anonymous> (http://localhost:5000/bundle.js:965:2), <anonymous>:27:14)
at DebugAppView._View_MainComponent1._handle_click_0_0 (MainComponent.ngfactory.js:172:35)
at eval (eval at <anonymous> (http://localhost:5000/common.js:1731:2), <anonymous>:381:24)
at eval (eval at <anonymous> (http://localhost:5000/common.js:2322:2), <anonymous>:255:36)
at eval (eval at <anonymous> (http://localhost:5000/common.js:2364:2), <anonymous>:27:111)
at ZoneDelegate.invoke (eval at <anonymous> (http://localhost:5000/vendor.js:472:2), <anonymous>:332:29)
at Object.onInvoke (eval at <anonymous> (http://localhost:5000/common.js:1551:2), <anonymous>:53:41)
at ZoneDelegate.invoke (eval at <anonymous> (http://localhost:5000/vendor.js:472:2), <anonymous>:331:35)
at Zone.runGuarded (eval at <anonymous> (http://localhost:5000/vendor.js:472:2), <anonymous>:239:48)
答案 0 :(得分:0)
您的数据存储是个好主意,但我发现您的实施存在一些问题。最大的一点是,当组件调用Service.getDetaileInfo
时,它需要一个Observable<Card>
,但这在代码的两个实例中失败:
//this returns a Card instead of an Observable<Card>
if (this.dataStore.length > 0)... return New Card
//this never seems to be true since you never assign anything to this.observable
else if (this.observable) return this.observable
我的服务看起来像:
//object that holds cards already fetched from server
private cache = {};
private url = '...';
/** takes Card.name and returns Observable that emits detailed info
from the cache if possible, from the server if not */
public getDetailedInfo(name):Observable<Card> {
// if a Card by that name is in the cache, return it as an Observable
if (this.cache[name]) return Observable.of(this.cache[name]);
//call the server and convert results to JS object and access .data
return this.http.get('...').map( res => res.json().data)
// transform object to a new Card
.map(data => new Card(data.name, data.card_type, data.text))
// store result in the cache, under the card's name
.do(card => this.cache[card.name] = card)
}
在组件中,您可以在需要详细信息时致电Service.getDetailedInfo()
。该组件不需要自己的数据存储区。