将对象转换为数组然后每隔几秒显示一个元素
Convert Object to Array then display one element every few seconds
我像这样在我的服务中调用 API
getItems(): Observable<{}> {
return this.http.get(<path>)
.pipe(
pluck('items'),
);
}
returns 数据的形状:
items: Object { key: value, key: value, key: value ...}
我像这样在我的组件中订阅了这个
items$!: any;
constructor(private readonly service: Service) { }
ngOnInit(): void {
this.service.getItems().subscribe(items => this.items$ = items);
}
并像这样在我的模板中显示它们
<div *ngFor="let item of items$ | keyvalue">
<mat-card>
<mat-card-header>
{{item.key}}
</mat-card-header>
<mat-card-content>
{{item.value}}
</mat-card-content>
</mat-card>
</div>
但是,我真正想要的是每隔几秒左右一次循环显示这些项目,而不是一次显示所有项目。我也想只进行一次 http 调用来完成此操作。我环顾四周,发现了解决方案的一些细节,但是,它通常至少涉及将对象转换为数组,然后可能使用某种 Subject 来观察订阅的原始可观察对象?这样做的干净方法是什么?谢谢。
一种解决方案是将数据从您的 API 转换为具有以下结构的数组:
const apiData = [{ a: 1 }, { b: 2 }, { c: 3 }, { d: 4 }, { e: 5 }, { f: 6 }];
接下来您可以使用以下使用 bufferCount
, concatMap
and delay
运算符的代码
data = [];
from(apiData)
.pipe(
bufferCount(1),
concatMap(objs => of(objs).pipe(delay(3000)))
)
.subscribe(e => {
this.data.push(e);
});
在模板上
<div *ngFor="let item of data">
{{item | json}} <-- tweak around with it to get exact details you need -->
</div>
创建一个每 5 秒发出一个值并与所有订阅者共享相同值的流。
item$: Observable<Item>;
ngOnInit(): void {
this.item$ = this.service.getItems().pipe(
switchMap(items => zip(
from(items),
timer(0,5000)
)),
map(([x,_]) => x),
share()
);
}
订阅流。异步管道是 angular
的最佳方式
<div>
<mat-card>
<mat-card-header>
{{(item$ | async).key}}
</mat-card-header>
<mat-card-content>
{{(item$ | async).value}}
</mat-card-content>
</mat-card>
</div>
更新 - 使用自定义运算符
function intervalArray<T>(milliseconds = 1000): OperatorFunction<T[], T> {
return s => s.pipe(
concatMap((a: T[]) => zip(
from(a),
timer(0, milliseconds)
).pipe(
map(([x,_]) => x)
))
);
}
ngOnInit(): void {
this.item$ = this.service.getItems().pipe(
intervalArray(5000),
share()
);
}
谢谢尼古拉斯先生。你帮了大忙。我将 Mrk 的回答标记为答案,因为我基本上使用了他们的代码。以防万一有人对是什么解决了我在评论中提到的几件事感到好奇,并希望在上下文中查看整个解决方案,这就是我所做的全部内容
//in the service
getItems(): Observable<{}> {
return this.http.get(<URL>)
.pipe(
pluck('items'),
);
}
//in the template, this change stopped the initial null issue I was having
<div *ngIf="item$ | async as state">
<mat-card>
<mat-card-header>
{{state.currencyPair}}
</mat-card-header>
<mat-card-content>
{{state.exchangeRate}}
</mat-card-content>
</mat-card>
</div>
//in the component
item$!: Observable<Item>;
constructor(private readonly service: Service) { }
ngOnInit(): void {
this.item$ = this.service.getItems().pipe(
switchMap(items => zip(
from(this.objectToArray(items)),
timer(0,5000)
)),
map(([x,_]) => x),
shareReplay(1)
);
}
objectToArray(object: {}) {
let items: Item[] = [];
for (const [key, value] of Object.entries(object)) {
items.push({ key : key, value : value })
}
return items;
}
//item.ts
export interface Item {
key: string;
value: any;
}
现在的问题是,在刷新 objectToArray 后得到一个未定义的对象显然是 API 的问题,因为我的免费计划不支持 https 加密,哈哈。我以为我通过从 URL 中取出 s 解决了这个问题,但是 耸耸肩 .
Nicholas,如果您想分享,我真的很想知道您的代码在上下文中如何工作。无论如何,我需要更深入地研究 Angular 库并了解更多信息。谢谢!
我像这样在我的服务中调用 API
getItems(): Observable<{}> {
return this.http.get(<path>)
.pipe(
pluck('items'),
);
}
returns 数据的形状:
items: Object { key: value, key: value, key: value ...}
我像这样在我的组件中订阅了这个
items$!: any;
constructor(private readonly service: Service) { }
ngOnInit(): void {
this.service.getItems().subscribe(items => this.items$ = items);
}
并像这样在我的模板中显示它们
<div *ngFor="let item of items$ | keyvalue">
<mat-card>
<mat-card-header>
{{item.key}}
</mat-card-header>
<mat-card-content>
{{item.value}}
</mat-card-content>
</mat-card>
</div>
但是,我真正想要的是每隔几秒左右一次循环显示这些项目,而不是一次显示所有项目。我也想只进行一次 http 调用来完成此操作。我环顾四周,发现了解决方案的一些细节,但是,它通常至少涉及将对象转换为数组,然后可能使用某种 Subject 来观察订阅的原始可观察对象?这样做的干净方法是什么?谢谢。
一种解决方案是将数据从您的 API 转换为具有以下结构的数组:
const apiData = [{ a: 1 }, { b: 2 }, { c: 3 }, { d: 4 }, { e: 5 }, { f: 6 }];
接下来您可以使用以下使用 bufferCount
, concatMap
and delay
运算符的代码
data = [];
from(apiData)
.pipe(
bufferCount(1),
concatMap(objs => of(objs).pipe(delay(3000)))
)
.subscribe(e => {
this.data.push(e);
});
在模板上
<div *ngFor="let item of data">
{{item | json}} <-- tweak around with it to get exact details you need -->
</div>
创建一个每 5 秒发出一个值并与所有订阅者共享相同值的流。
item$: Observable<Item>;
ngOnInit(): void {
this.item$ = this.service.getItems().pipe(
switchMap(items => zip(
from(items),
timer(0,5000)
)),
map(([x,_]) => x),
share()
);
}
订阅流。异步管道是 angular
的最佳方式<div>
<mat-card>
<mat-card-header>
{{(item$ | async).key}}
</mat-card-header>
<mat-card-content>
{{(item$ | async).value}}
</mat-card-content>
</mat-card>
</div>
更新 - 使用自定义运算符
function intervalArray<T>(milliseconds = 1000): OperatorFunction<T[], T> {
return s => s.pipe(
concatMap((a: T[]) => zip(
from(a),
timer(0, milliseconds)
).pipe(
map(([x,_]) => x)
))
);
}
ngOnInit(): void {
this.item$ = this.service.getItems().pipe(
intervalArray(5000),
share()
);
}
谢谢尼古拉斯先生。你帮了大忙。我将 Mrk 的回答标记为答案,因为我基本上使用了他们的代码。以防万一有人对是什么解决了我在评论中提到的几件事感到好奇,并希望在上下文中查看整个解决方案,这就是我所做的全部内容
//in the service
getItems(): Observable<{}> {
return this.http.get(<URL>)
.pipe(
pluck('items'),
);
}
//in the template, this change stopped the initial null issue I was having
<div *ngIf="item$ | async as state">
<mat-card>
<mat-card-header>
{{state.currencyPair}}
</mat-card-header>
<mat-card-content>
{{state.exchangeRate}}
</mat-card-content>
</mat-card>
</div>
//in the component
item$!: Observable<Item>;
constructor(private readonly service: Service) { }
ngOnInit(): void {
this.item$ = this.service.getItems().pipe(
switchMap(items => zip(
from(this.objectToArray(items)),
timer(0,5000)
)),
map(([x,_]) => x),
shareReplay(1)
);
}
objectToArray(object: {}) {
let items: Item[] = [];
for (const [key, value] of Object.entries(object)) {
items.push({ key : key, value : value })
}
return items;
}
//item.ts
export interface Item {
key: string;
value: any;
}
现在的问题是,在刷新 objectToArray 后得到一个未定义的对象显然是 API 的问题,因为我的免费计划不支持 https 加密,哈哈。我以为我通过从 URL 中取出 s 解决了这个问题,但是 耸耸肩 .
Nicholas,如果您想分享,我真的很想知道您的代码在上下文中如何工作。无论如何,我需要更深入地研究 Angular 库并了解更多信息。谢谢!