使用 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$;
}