Получение данных из JSON с использованием RxJS пытается вернуть массив и передать значения различным субъектам поведения - PullRequest
0 голосов
/ 29 января 2019

Во-первых, я открыт для других вещей, кроме предметов поведения?но это то, что работает для меня до сих пор.У меня есть приложение Nativescript, использующее последнюю сборку Angular7 и Nativescript 5.1. Я пытаюсь заполнить ListView в NS файлом json, и пока все работает хорошо.Но я хотел бы сделать больше с файлом конфигурации, чем просто с начальным просмотром списка.

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);
        })
      );
  }
}

Мой вопрос звучит так.Используя приведенный выше код, я получаю часть моего массива в разделе «результат».Но я также хотел бы получить конфигурацию и сохранить ее.Есть ли способ для меня сделать то же самое, что я делаю с данными ["результаты"] и сохранить его в this.config $ вместо this.items $

Я бы хотел, чтобы оба объекта изтот же JSON, но не нужно делать 2 звонка, чтобы все это настроить.Есть ли способ, которым я могу сделать 1 вызов в JSON, а затем сохранить различные объекты как субъекты поведения?

{
 "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 ключа.начало и конец (потому что config жаловался, что он уже использовался в какой-то другой зависимости).поэтому с началом и окончанием в моем JSON я делаю console.log, и я получаю оба ключа .. начало и конец.

новая проблема заключается в том, что мой исходный вызов имел MAP, который удалил все остальные дерьмо и простодал мне массив без видимого кода.новый материал дает мне кучу наблюдаемого контента вместе с ним ... мой текущий ListView теперь не заполняется новым кодом, хотя я знаю, что консольный журнал делает то, что мы хотим (в основном).

<RadListView [items]="items$ | async"

    ngOnInit() {
       this._dataItemService.fetch().subscribe();

       this.items$  = this._dataItemService.items$;
    }

Ответы [ 2 ]

0 голосов
/ 29 января 2019

Вы отбрасываете наблюдаемую цепочку здесь, выбивая второстепенную тему, но я полагаю, что это обсуждение в другой раз.

Чтобы следовать парадигме, которую вы уже используете, вы можете просто.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 будет выполнено для каждого подписчика, а также любой «оконечный» пункт должен быть его собственным подписчиком.Как и сейчас, у вас есть побочный эффект, который будет выдвигать новое значение к items$ для каждой подписываемой вещи.

То есть, если вы делаете:

let obs: Observable<any> = this.dataItemService.fetch();
obs.subscribe((items) => this.config$.next(items));
obs.subscribe((items) => this.otherConfig$.next(items));

Вы получите items$ в пределах dataItemService с одним и тем же значением дважды, потому что оно находится в цепочке .pipe, которая ведет к каждому .subscribe.Вместо этого вы можете подумать о том, чтобы разбить это назначение как собственное .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$;
}
0 голосов
/ 29 января 2019

Вам не нужна карта между ними, вы можете извлекать данные с помощью синтаксиса 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);
        })
      );
...