更新异步管道中使用的可观察对象的一部分
Updating part of an observable used in async pipe
我们有一个包含多个部分的页面。每个部分可以有一张卡片或一张table。可观察对象使用异步管道在 html 中绑定数据。现在我需要更新 table 之一而不刷新整个可观察对象。
loadPageData(Id): void {
this.sections$ = this.psService.getLoadPageData(Id).pipe(
switchMap(sections => forkJoin(
sections.map(section => this.psService.getSectionData(section.sectionID).pipe(
map(card => Object.assign({}, section, { card })),
switchMap(c => c.card.map(card => iif(() => card.cardTypeId === 3,
from(this.psService.getTable(this.tablePerodID).pipe(map(table => Object.assign({}, c, { table })))),
of(c))))
).concatAll()
))
));
}
updateTable(sectionId, tablePerodID) {
let tableData;
this.psService.getTable(tablePerodID).subscribe((data) => {
tableData = data;
});
this.sections$.forEach(sections => {
sections.forEach(section => {
if (section.sectionID === sectionId) {
section.table = sectionData;
}
});
});
}
而 HTML 就像:
<div *ngFor="let section of sections$ | async;">
<div *ngFor="let card of section.card | sort:'displayOrder';">
<app-card></app-card>
<div *ngIf="card.cardTypeName === 'Table'">
<app-table></app-table>
</div>
</div>
</div>
现在的问题是,当我尝试使用 updateTable [当用户更改 tablePerodID] 为 table 加载数据时,它什么也没做。我试过 .next()
但它更新了整个 section$
。反正我只能更新table?
这似乎是对管道运作方式的误解。
明喻
想想水管。
假设您想要一个水龙头来倒糖水。
如果你从水龙头里取一杯水,然后往里面加糖,你就不能再把那水放回水龙头里了。
解决办法是在接水之前加一根带加糖系统的管子。
rxjs 管道是一样的,一旦你订阅,就没有回头路了。 (除非您创建一个新管道并将水倒入其中;)
解决方案是通过管道传输所有内容。只有 subscribe
当你想获得价值时。这也有性能改进。
解决方案
this._cache$: BehaviorSubject<Section[]> = new BehaviorSubject<Section[]> ([]);
this.sections$: Observable<Section[]>;
loadPageData(id: number): void {
// subcribe once and save the values in the cache
this.fetchPageData(Id).subscribe(data => this._cache$.next(data));
// section$ will emit values when caché changes
this.sections$ = this._cache$.asObservable();
}
fetchPageData(Id): Observable<Section[]> {
// call your data service
return this.psService.getLoadPageData(Id).pipe(
//...
);
}
updateTable(sectionId, tablePerodID) {
let tableData;
this.psService.getTable(tablePerodID).subscribe((data) => {
tableData = data;
});
this.sections$ = this.sections$.pipe(
map(sections => sections.map(section =>
{
if (section.sectionID === sectionId) {
section.table = tableData;
}
})
);
}
不是订阅可观察对象,而是管道更新操作。
updateTable
将更新 sections$
可观察对象,html 异步管道将更新结果。
使用 _cache$
有另一个性能改进,因为每次更新管道时它都不会调用您的数据服务。 (没必要用)
澄清:这将更新您应用中的管道,而不是数据库或任何地方的数据。
感谢@adrisons 让我想到了缓存。这是对我有用的解决方案。它与@adrisons 的回答略有不同,因为它不使用 observable。
_cached: any;
sections$: Observable<any>;
loadPageData(Id): void {
// Load data from server
this.sections$ = this.psService.getLoadPageData(Id).pipe(
switchMap(sections => forkJoin(
sections.map(section => this.psService.getSectionData(section.sectionID).pipe(
map(card => Object.assign({}, section, { card })),
switchMap(c => c.card.map(card => iif(() => card.cardTypeId === 3,
from(this.psService.getTable(this.tablePerodID)
.pipe(map(table => Object.assign({}, c, { table })))),
of(c))))
).concatAll()
))
), first(), // Tap and get the first emit and assign to cache
tap((data: any) => {
this._cached = data // Caching the data without subscribing.
}));
}
updateTable(sectionId, tablePerodID) {
// Get table Data from backend and update cache
this.psService.getTable(tablePerodID).subscribe((data) => {
this._cached.map(section => {
if (section.sectionID === sectionId) {
section.table = data;
}
});
});
// Refresh async observable from cache
this.refreshFromCache();
}
refreshFromCache() {
this.sections$ = of(this._cached)
}
我们有一个包含多个部分的页面。每个部分可以有一张卡片或一张table。可观察对象使用异步管道在 html 中绑定数据。现在我需要更新 table 之一而不刷新整个可观察对象。
loadPageData(Id): void {
this.sections$ = this.psService.getLoadPageData(Id).pipe(
switchMap(sections => forkJoin(
sections.map(section => this.psService.getSectionData(section.sectionID).pipe(
map(card => Object.assign({}, section, { card })),
switchMap(c => c.card.map(card => iif(() => card.cardTypeId === 3,
from(this.psService.getTable(this.tablePerodID).pipe(map(table => Object.assign({}, c, { table })))),
of(c))))
).concatAll()
))
));
}
updateTable(sectionId, tablePerodID) {
let tableData;
this.psService.getTable(tablePerodID).subscribe((data) => {
tableData = data;
});
this.sections$.forEach(sections => {
sections.forEach(section => {
if (section.sectionID === sectionId) {
section.table = sectionData;
}
});
});
}
而 HTML 就像:
<div *ngFor="let section of sections$ | async;">
<div *ngFor="let card of section.card | sort:'displayOrder';">
<app-card></app-card>
<div *ngIf="card.cardTypeName === 'Table'">
<app-table></app-table>
</div>
</div>
</div>
现在的问题是,当我尝试使用 updateTable [当用户更改 tablePerodID] 为 table 加载数据时,它什么也没做。我试过 .next()
但它更新了整个 section$
。反正我只能更新table?
这似乎是对管道运作方式的误解。
明喻
想想水管。
假设您想要一个水龙头来倒糖水。
如果你从水龙头里取一杯水,然后往里面加糖,你就不能再把那水放回水龙头里了。
解决办法是在接水之前加一根带加糖系统的管子。
rxjs 管道是一样的,一旦你订阅,就没有回头路了。 (除非您创建一个新管道并将水倒入其中;)
解决方案是通过管道传输所有内容。只有 subscribe
当你想获得价值时。这也有性能改进。
解决方案
this._cache$: BehaviorSubject<Section[]> = new BehaviorSubject<Section[]> ([]);
this.sections$: Observable<Section[]>;
loadPageData(id: number): void {
// subcribe once and save the values in the cache
this.fetchPageData(Id).subscribe(data => this._cache$.next(data));
// section$ will emit values when caché changes
this.sections$ = this._cache$.asObservable();
}
fetchPageData(Id): Observable<Section[]> {
// call your data service
return this.psService.getLoadPageData(Id).pipe(
//...
);
}
updateTable(sectionId, tablePerodID) {
let tableData;
this.psService.getTable(tablePerodID).subscribe((data) => {
tableData = data;
});
this.sections$ = this.sections$.pipe(
map(sections => sections.map(section =>
{
if (section.sectionID === sectionId) {
section.table = tableData;
}
})
);
}
不是订阅可观察对象,而是管道更新操作。
updateTable
将更新 sections$
可观察对象,html 异步管道将更新结果。
使用 _cache$
有另一个性能改进,因为每次更新管道时它都不会调用您的数据服务。 (没必要用)
澄清:这将更新您应用中的管道,而不是数据库或任何地方的数据。
感谢@adrisons 让我想到了缓存。这是对我有用的解决方案。它与@adrisons 的回答略有不同,因为它不使用 observable。
_cached: any;
sections$: Observable<any>;
loadPageData(Id): void {
// Load data from server
this.sections$ = this.psService.getLoadPageData(Id).pipe(
switchMap(sections => forkJoin(
sections.map(section => this.psService.getSectionData(section.sectionID).pipe(
map(card => Object.assign({}, section, { card })),
switchMap(c => c.card.map(card => iif(() => card.cardTypeId === 3,
from(this.psService.getTable(this.tablePerodID)
.pipe(map(table => Object.assign({}, c, { table })))),
of(c))))
).concatAll()
))
), first(), // Tap and get the first emit and assign to cache
tap((data: any) => {
this._cached = data // Caching the data without subscribing.
}));
}
updateTable(sectionId, tablePerodID) {
// Get table Data from backend and update cache
this.psService.getTable(tablePerodID).subscribe((data) => {
this._cached.map(section => {
if (section.sectionID === sectionId) {
section.table = data;
}
});
});
// Refresh async observable from cache
this.refreshFromCache();
}
refreshFromCache() {
this.sections$ = of(this._cached)
}