使用 RxJS 尝试 return 数组从 JSON 获取数据并将值传递给不同的行为主体
Getting data from JSON using RxJS trying to return array and pass values to different behavior subjects
首先,我对行为学科以外的其他事物持开放态度?但到目前为止,这对我有用。我有一个使用最新的 Angular7 构建和 Nativescript 5.1 的 Nativescript 应用程序我正在尝试使用 json 文件填充 NS 中的 ListView 并且到目前为止一切正常。但是我想用配置文件做更多的事情,而不仅仅是初始列表视图。
import { HttpClient } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { BehaviorSubject, Observable, of } from "rxjs";
import { catchError, map, tap } from "rxjs/operators";
import { IMenuItem } from "~/app/menuItem";
@Injectable({
providedIn: "root"
})
export class DataItemService {
items$ = new BehaviorSubject<Array<IMenuItem>>([]);
constructor(private http: HttpClient) { }
clear(): void {
this.items$.next([]);
}
fetch(): Observable<any> {
this.clear();
return this.http.get("https://example.com/config.json")
.pipe(
map((data) => {
return (data["result"]) ? data["result"] : false;
}
),
tap((items) => { if (items) { this.items$.next(items); }}),
catchError((err) => {
return of(false);
})
);
}
}
我的问题是这样的。使用上面的代码,我在 "result" 部分获得了数组的一部分。但我也想获取配置并保存它。有没有办法让我做与数据["results"]完全相同的事情并将其保存到this.config$而不是this.items$
我想要来自同一个 json 的两个对象,但不必调用 2 次来设置它。有没有一种方法可以对 JSON 进行 1 次调用,然后将不同的对象保存为行为主体?
{
"config": [
{
"debug": true
}
],
"result": [
{
"id": 0,
"title": "Home",
"titleFontSize": 16,
"iconFontSize": 30,
"subtitle": "This is the subtitle for messages",
"image": "",
"icon": "fa-home",
"url": "/home",
"sidebar": true,
"mainmenu": false,
"bg": "#ffdc00",
"titleColor": "white",
"subtitleColor": "white",
"squarebg": "rgba(0,0,0,.8)"
}
]
}
--- 编辑 ---
使用下面的答案作为灵感.. 我有这个
fetch(): Observable<any> {
this.clear();
return this.http.get("https://example.com/config.json")
.pipe(
tap(({start, finish}) => {
if (start) {
this.items$.next(start);
console.log("ITEMS ARE " + JSON.stringify(this.items$.value));
}
if (finish) {
this.config$.next(finish);
console.log("CONFIG IS " + JSON.stringify(this.config$.value));
}
}
));
现在我将 JSON 修改为有 2 个键。开始和完成(因为配置抱怨它已经在其他一些依赖项中使用)。所以在我的 JSON 中开始和完成我做了 console.log 并且我得到了两个键..开始和完成。
新问题是我最初的调用有一个 MAP,它删除了所有其他废话,只给了我没有可观察代码的数组。新的东西给了我一堆可观察的内容..我当前的 ListView 现在没有用新代码填充,即使我知道控制台日志正在做我们想要的(大部分)。
<RadListView [items]="items$ | async"
ngOnInit() {
this._dataItemService.fetch().subscribe();
this.items$ = this._dataItemService.items$;
}
你真的不需要中间的映射,你可以用ES6语法提取数据。
this.http.get("https://example.com/config.json")
.pipe(
tap(({result,config})) => {
if (result) this.items$.next(items);
if (config) this.config$.next(config);
}),
catchError((err) => {
return of(false);
})
);
您在这里打破了次要主题,从而抛弃了可观察链接,但我想这是另一次讨论。
要遵循您已经在使用的范例,您可以 .subscribe
并在别处使用它。无论在哪个上下文中调用 fetch
,您都可以附加到它的结果并将其作为链的末尾处理,如果您愿意的话。
config: Subject<any> = new Subject<any>();
constructor(private dataItemService: DataItemService) {
}
fetch(): void {
this.dataItemService.fetch().subscribe((items: any) => {
this.config$.next(items);
});
}
您应该知道您的 .pipe
将针对每个订阅者执行,并且任何 "termination" 点都应该是它自己的订阅者。就像现在一样,这里发生了一个副作用,它将为每个订阅的东西推送一个新值到 items$
。
也就是说,如果你这样做:
let obs: Observable<any> = this.dataItemService.fetch();
obs.subscribe((items) => this.config$.next(items));
obs.subscribe((items) => this.otherConfig$.next(items));
您将在 dataItemService
中将 items$
推入两次相同的值,因为它位于通向每个 .subscribe
的 .pipe
链中。相反,您可能会考虑将该分配分解为它自己的 .subscribe
或 放入 pipe(share())
以确保在最终通知之前压缩所有管道所有订阅者。
fetch(): Observable<any> {
this.clear();
let obs$: Observable<any> = this.http.get("https://example.com/config.json")
.pipe(map((data) => (data["result"]) ? data["result"] : false ))
.pipe(share()) // Processes 'data' only once, returning the same result to each subscriber
catchError((err) => {
return of(false);
})
);
obs$.subscribe((items) => this.items$.next(items));
return obs$;
}
首先,我对行为学科以外的其他事物持开放态度?但到目前为止,这对我有用。我有一个使用最新的 Angular7 构建和 Nativescript 5.1 的 Nativescript 应用程序我正在尝试使用 json 文件填充 NS 中的 ListView 并且到目前为止一切正常。但是我想用配置文件做更多的事情,而不仅仅是初始列表视图。
import { HttpClient } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { BehaviorSubject, Observable, of } from "rxjs";
import { catchError, map, tap } from "rxjs/operators";
import { IMenuItem } from "~/app/menuItem";
@Injectable({
providedIn: "root"
})
export class DataItemService {
items$ = new BehaviorSubject<Array<IMenuItem>>([]);
constructor(private http: HttpClient) { }
clear(): void {
this.items$.next([]);
}
fetch(): Observable<any> {
this.clear();
return this.http.get("https://example.com/config.json")
.pipe(
map((data) => {
return (data["result"]) ? data["result"] : false;
}
),
tap((items) => { if (items) { this.items$.next(items); }}),
catchError((err) => {
return of(false);
})
);
}
}
我的问题是这样的。使用上面的代码,我在 "result" 部分获得了数组的一部分。但我也想获取配置并保存它。有没有办法让我做与数据["results"]完全相同的事情并将其保存到this.config$而不是this.items$
我想要来自同一个 json 的两个对象,但不必调用 2 次来设置它。有没有一种方法可以对 JSON 进行 1 次调用,然后将不同的对象保存为行为主体?
{
"config": [
{
"debug": true
}
],
"result": [
{
"id": 0,
"title": "Home",
"titleFontSize": 16,
"iconFontSize": 30,
"subtitle": "This is the subtitle for messages",
"image": "",
"icon": "fa-home",
"url": "/home",
"sidebar": true,
"mainmenu": false,
"bg": "#ffdc00",
"titleColor": "white",
"subtitleColor": "white",
"squarebg": "rgba(0,0,0,.8)"
}
]
}
--- 编辑 ---
使用下面的答案作为灵感.. 我有这个
fetch(): Observable<any> {
this.clear();
return this.http.get("https://example.com/config.json")
.pipe(
tap(({start, finish}) => {
if (start) {
this.items$.next(start);
console.log("ITEMS ARE " + JSON.stringify(this.items$.value));
}
if (finish) {
this.config$.next(finish);
console.log("CONFIG IS " + JSON.stringify(this.config$.value));
}
}
));
现在我将 JSON 修改为有 2 个键。开始和完成(因为配置抱怨它已经在其他一些依赖项中使用)。所以在我的 JSON 中开始和完成我做了 console.log 并且我得到了两个键..开始和完成。
新问题是我最初的调用有一个 MAP,它删除了所有其他废话,只给了我没有可观察代码的数组。新的东西给了我一堆可观察的内容..我当前的 ListView 现在没有用新代码填充,即使我知道控制台日志正在做我们想要的(大部分)。
<RadListView [items]="items$ | async"
ngOnInit() {
this._dataItemService.fetch().subscribe();
this.items$ = this._dataItemService.items$;
}
你真的不需要中间的映射,你可以用ES6语法提取数据。
this.http.get("https://example.com/config.json")
.pipe(
tap(({result,config})) => {
if (result) this.items$.next(items);
if (config) this.config$.next(config);
}),
catchError((err) => {
return of(false);
})
);
您在这里打破了次要主题,从而抛弃了可观察链接,但我想这是另一次讨论。
要遵循您已经在使用的范例,您可以 .subscribe
并在别处使用它。无论在哪个上下文中调用 fetch
,您都可以附加到它的结果并将其作为链的末尾处理,如果您愿意的话。
config: Subject<any> = new Subject<any>();
constructor(private dataItemService: DataItemService) {
}
fetch(): void {
this.dataItemService.fetch().subscribe((items: any) => {
this.config$.next(items);
});
}
您应该知道您的 .pipe
将针对每个订阅者执行,并且任何 "termination" 点都应该是它自己的订阅者。就像现在一样,这里发生了一个副作用,它将为每个订阅的东西推送一个新值到 items$
。
也就是说,如果你这样做:
let obs: Observable<any> = this.dataItemService.fetch();
obs.subscribe((items) => this.config$.next(items));
obs.subscribe((items) => this.otherConfig$.next(items));
您将在 dataItemService
中将 items$
推入两次相同的值,因为它位于通向每个 .subscribe
的 .pipe
链中。相反,您可能会考虑将该分配分解为它自己的 .subscribe
或 放入 pipe(share())
以确保在最终通知之前压缩所有管道所有订阅者。
fetch(): Observable<any> {
this.clear();
let obs$: Observable<any> = this.http.get("https://example.com/config.json")
.pipe(map((data) => (data["result"]) ? data["result"] : false ))
.pipe(share()) // Processes 'data' only once, returning the same result to each subscriber
catchError((err) => {
return of(false);
})
);
obs$.subscribe((items) => this.items$.next(items));
return obs$;
}