回到学习Angular并扩展英雄之旅教程。我有一个共享数据服务,可以将数据加载到BehaviorSubject中。问题是,当我尝试使用* ngFor迭代数据时,我得到“找不到不同的支持对象”错误。从所有其他问题,我得到它试图绑定到一个对象而不是一个数组,但对于我的生活,我无法弄清楚为什么。或者需要将哪个对象转换为数组。
我正在使用Angular 5.0.5。有趣的是,这与Angular 4有关,但显然我在升级中已经破坏了一些东西。
对我做错了什么的想法?除了一切。 :D lol
这是我的服务
import { Injectable, EventEmitter } from '@angular/core';
import { HttpHeaders, HttpClient } from '@angular/common/http';
import { Subject } from 'rxjs/Subject';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Observable } from 'rxjs/Observable';
import { Hero } from '../models/hero';
@Injectable()
export class HeroService {
private heroesUrl = 'api/heroes';
private headers = new HttpHeaders({'Content-Type': 'application/json'});
private loadingSubject = new BehaviorSubject<boolean>(false);
private dataSubject = new BehaviorSubject<Hero[]>([]);
private http: HttpClient;
constructor(http: HttpClient) {
this.http = http;
}
public getLoadingStream(): Observable<boolean> {
return this.loadingSubject.asObservable();
}
public getDataStream(): Observable<Hero[]> {
return this.dataSubject.asObservable();
}
public load(): void {
this.loadingSubject.next(true);
this.http.get<Hero[]>(this.heroesUrl).subscribe(data => {
this.dataSubject.next(data);
this.loadingSubject.next(false);
});
}
public search(term: string): void {
this.loadingSubject.next(true);
this.http
.get<Hero[]>(`${this.heroesUrl}/?name=${term}`)
.subscribe(data => {
this.dataSubject.next(data);
this.loadingSubject.next(false);
});
}
}
列出组件
import { Component, OnInit, OnDestroy, Input, Output, EventEmitter } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Subscription } from 'rxjs/Subscription';
import { HeroService } from '../../services/hero.service';
import { Hero } from '../../models/hero';
@Component({
selector: 'hero-list',
templateUrl: './hero-list.component.html',
styleUrls: ['./hero-list.component.css']
})
export class HeroListComponent implements OnInit {
private dataSubscription: Subscription;
private loadingSubscription: Subscription;
private heroService: HeroService;
heroes: Hero[] = [];
isLoading: boolean;
@Output()
public onHeroSelected = new EventEmitter<Hero>();
constructor(heroService: HeroService) {
this.heroService = heroService;
}
ngOnInit() {
this.loadingSubscription = this.heroService.getLoadingStream()
.subscribe(loading => {
this.isLoading = loading;
});
this.dataSubscription = this.heroService.getDataStream()
.subscribe(data => {
this.heroes = data;
});
}
ngOnDestory() {
this.dataSubscription.unsubscribe();
this.loadingSubscription.unsubscribe();
}
onSelect(hero: Hero) {
this.onHeroSelected.emit(hero);
}
}
列出模板
<div *ngIf="isLoading">Loading ...</div>
<div *ngIf="!isLoading" class="ui relaxed divided list">
<div *ngFor="let hero of heroes" class="item" (click)="onSelect(hero)">
<span class="ui blue circular label">{{ hero.id }}</span>
<div class="content">
<a class="header">{{ hero.name }}</a>
<div class="description">...</div>
</div>
</div>
</div>
答案 0 :(得分:0)
不是定义一个返回一个observable的函数,你不应该定义一个实际上是可观察的属性吗?例如:
<强>服务强>
public heroDataStream: Observable<Hero[]> = this.dataSubject.asObservable();
然后您将直接订阅heroDataStream
。这通常是我如何将BehaviorSubjects转换为observables而不是将它们包装在一个新函数中。
您可能遇到了一个冷和热的问题,在调用订阅之前,Observable没有被创建,因为它的定义在函数内。换句话说它很冷。你希望它的声明立即发生,这意味着它需要很热并且准备好了。因此,将其定义为服务中的属性会使用该服务声明它。我可能是错的,当谈到RxJs以及如何将所有内容都假装起来时,这肯定会让我深入了解我的知识深度。
答案 1 :(得分:0)
呃,我讨厌回答我自己的问题,但这是一个很大的&#34; d&#39;哦&#34;。
问题的根本原因是我使用的是In-Memory-Web-API,并没有意识到它正在将响应封装在数据对象中。
因此错误消息是正确的,它试图迭代对象{data:[]}而不是数组。
升级In-Memory-Web-API并将false放入数据封装
HttpClientInMemoryWebApiModule.forRoot(InMemoryDataService, {dataEncapsulation: false})
解决了这个问题。
非常感谢JB Nizet指出我正确的方向!