Angular2 - 一个商店,多个组件,不同的 API 调用
Angular2 - one store, multiple component, different API call
假设我有一个父组件 HomeComponent
,其中包含多个嵌套组件 TeamsStandingComponent
。
TeamsStandingComponent
必须显示从 API 调用收集的数据,使用公共但私有的存储,TeamsStandingStore
。
现在我将向您展示我的代码。
HomeComponent
:
import { Component } from '@angular/core';
@Component({
selector: 'home',
templateUrl: '../templates/home.html'
})
export class HomeComponent {
constructor(
) {}
}
这是 HomeComponent
模板:
<div class="top-three-standings__wrapper">
<teams-standing #standing1 [leagueId]="426"></teams-standing>
<teams-standing #standing2 [leagueId]="439"></teams-standing>
</div>
这是TeamsStandingComponent
:
import { Component, AfterViewInit, NgZone, ChangeDetectorRef,
ElementRef, Input } from '@angular/core';
import { TeamsStandingStore } from '../stores/teams-standing';
import { HttpClient } from '../services/http-client'; // you can ignore this
@Component({
selector: 'teams-standing',
providers: [HttpClient], // you can ignore this
templateUrl: '../templates/teams-standing.html'
})
export class TeamsStandingComponent implements AfterViewInit {
@Input() private teams: Object;
@Input() private leagueId: string;
private teamsStandingStore: TeamsStandingStore;
constructor(
private TeamsStandingStore: TeamsStandingStore,
private ngzone: NgZone,
private cdref: ChangeDetectorRef
) {
console.clear();
this.teamsStandingStore = TeamsStandingStore;
}
public ngAfterViewInit () {
this.ngzone.runOutsideAngular( () => {
this.teamsStandingStore.standings
.subscribe( (data) => {
this.teams = data;
this.cdref.detectChanges();
} );
});
this.http.get(`competitions/` + this.leagueId + `/leagueTable`)
.subscribe(
(data: any) => this.teamsStandingStore.showStandings(data.json()),
(error) => console.log(error)
);
}
}
这是 TeamsStandingComponent
模板:
<div class="teams-standing__table">
<h2>{{leagueId}} - {{teams?._links?.competition?.href}}</h2>
<h3>{{teams?.leagueCaption}}</h3>
<div *ngFor="let team of teams?.standing">
{{team.teamName}}
{{team.crestURI}}
</div>
</div>
最后是 TeamStandingStore
:
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Rx';
@Injectable()
export class TeamsStandingStore {
private standings: Subject<any> = new Subject<any>();
private showStands: Subject<any> = new Subject<any>();
constructor() {
this.showStands
.subscribe(this.standings);
}
public showStandings(standings) {
this.showStands.next(standings);
}
}
我的问题是那些嵌套组件 TeamsStandingComponent
显示相同的数据,即使 每个 组件调用不同的端点 - 就像你一样可以看到 - 并且有不同的反应。
PS:我正在使用@angular v.2.4.9 和 rxjs v.5.0.2
我相信所有嵌套组件都获得相同的值,因为它们都使用 TeamStandingStore
的相同实例。
您没有在提供 TeamStandingStore
的地方显示模块,但我猜您是在模块级别提供的。这意味着每个组件都获得了相同的 Store 实例,因此都订阅了相同的 standings
observable。
在这种情况下,您可能想要做的是在组件级别而不是模块级别提供商店,这样每个 TeamStandingComponent
都有自己的实例。您可以通过在组件装饰器中提供 TeamStandingStore
来做到这一点:
@Component({
selector: 'teams-standing',
providers: [HttpClient, TeamStandingStore], // <- insert TeamStandingStore here
templateUrl: '../templates/teams-standing.html'
})
export class TeamsStandingComponent implements AfterViewInit {
@Input() private teams: Object;
@Input() private leagueId: string;
private teamsStandingStore: TeamsStandingStore;
constructor(
private TeamsStandingStore: TeamsStandingStore,
private ngzone: NgZone,
private cdref: ChangeDetectorRef
) {
console.clear();
this.teamsStandingStore = TeamsStandingStore;
}
假设我有一个父组件 HomeComponent
,其中包含多个嵌套组件 TeamsStandingComponent
。
TeamsStandingComponent
必须显示从 API 调用收集的数据,使用公共但私有的存储,TeamsStandingStore
。
现在我将向您展示我的代码。
HomeComponent
:
import { Component } from '@angular/core';
@Component({
selector: 'home',
templateUrl: '../templates/home.html'
})
export class HomeComponent {
constructor(
) {}
}
这是 HomeComponent
模板:
<div class="top-three-standings__wrapper">
<teams-standing #standing1 [leagueId]="426"></teams-standing>
<teams-standing #standing2 [leagueId]="439"></teams-standing>
</div>
这是TeamsStandingComponent
:
import { Component, AfterViewInit, NgZone, ChangeDetectorRef,
ElementRef, Input } from '@angular/core';
import { TeamsStandingStore } from '../stores/teams-standing';
import { HttpClient } from '../services/http-client'; // you can ignore this
@Component({
selector: 'teams-standing',
providers: [HttpClient], // you can ignore this
templateUrl: '../templates/teams-standing.html'
})
export class TeamsStandingComponent implements AfterViewInit {
@Input() private teams: Object;
@Input() private leagueId: string;
private teamsStandingStore: TeamsStandingStore;
constructor(
private TeamsStandingStore: TeamsStandingStore,
private ngzone: NgZone,
private cdref: ChangeDetectorRef
) {
console.clear();
this.teamsStandingStore = TeamsStandingStore;
}
public ngAfterViewInit () {
this.ngzone.runOutsideAngular( () => {
this.teamsStandingStore.standings
.subscribe( (data) => {
this.teams = data;
this.cdref.detectChanges();
} );
});
this.http.get(`competitions/` + this.leagueId + `/leagueTable`)
.subscribe(
(data: any) => this.teamsStandingStore.showStandings(data.json()),
(error) => console.log(error)
);
}
}
这是 TeamsStandingComponent
模板:
<div class="teams-standing__table">
<h2>{{leagueId}} - {{teams?._links?.competition?.href}}</h2>
<h3>{{teams?.leagueCaption}}</h3>
<div *ngFor="let team of teams?.standing">
{{team.teamName}}
{{team.crestURI}}
</div>
</div>
最后是 TeamStandingStore
:
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Rx';
@Injectable()
export class TeamsStandingStore {
private standings: Subject<any> = new Subject<any>();
private showStands: Subject<any> = new Subject<any>();
constructor() {
this.showStands
.subscribe(this.standings);
}
public showStandings(standings) {
this.showStands.next(standings);
}
}
我的问题是那些嵌套组件 TeamsStandingComponent
显示相同的数据,即使 每个 组件调用不同的端点 - 就像你一样可以看到 - 并且有不同的反应。
PS:我正在使用@angular v.2.4.9 和 rxjs v.5.0.2
我相信所有嵌套组件都获得相同的值,因为它们都使用 TeamStandingStore
的相同实例。
您没有在提供 TeamStandingStore
的地方显示模块,但我猜您是在模块级别提供的。这意味着每个组件都获得了相同的 Store 实例,因此都订阅了相同的 standings
observable。
在这种情况下,您可能想要做的是在组件级别而不是模块级别提供商店,这样每个 TeamStandingComponent
都有自己的实例。您可以通过在组件装饰器中提供 TeamStandingStore
来做到这一点:
@Component({
selector: 'teams-standing',
providers: [HttpClient, TeamStandingStore], // <- insert TeamStandingStore here
templateUrl: '../templates/teams-standing.html'
})
export class TeamsStandingComponent implements AfterViewInit {
@Input() private teams: Object;
@Input() private leagueId: string;
private teamsStandingStore: TeamsStandingStore;
constructor(
private TeamsStandingStore: TeamsStandingStore,
private ngzone: NgZone,
private cdref: ChangeDetectorRef
) {
console.clear();
this.teamsStandingStore = TeamsStandingStore;
}