Передача значений из нескольких наблюдаемых - PullRequest
0 голосов
/ 23 февраля 2019

В моем сервисе Angular у меня есть следующие методы:

// creates an Item and returns the ID of the created Item
createItem(item: Item): Observable<ItemId> {
    return this.http.post<ItemId>('some_api_url', item);
}

// returns all Items
getAllItems(): Observable<Item[]> {
    return this.http.get<Item[]>('some_api_url');
}

В моем шаблоне я показываю элементы в списке.

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

this.itemService.createItem(item)
    .pipe(
      switchMap(createdId => this.itemService.getAllItems())
    ).subscribe(result => {
      this.items = result;
    });

Это, похоже, работает нормально, но в конце я хотел бы сделать некоторыеобработка createdId также:

this.itemService.createItem(item)
    .pipe(
      switchMap(createdId => this.itemService.getAllItems())
    ).subscribe(result => {
      this.items = result;

      // i would like to use createdId here as well
    });

Итак, я придумал следующее:

this.itemService.createItem(item)
    .pipe(
      switchMap(createdId =>
         combineLatest(this.itemService.getAllItems(), of(createdId)))
    ).subscribe(result => {
      this.items = result[0];

      // doing some stuff with result[1], which is the value of createdId
    });

Но мне нужно использовать combineLatest внутри switchMap иЯвный make createdId an Observable заставляет меня задуматься о том, является ли это хорошим решением.

Так что в основном я хотел бы создать и элемент, обновить список (когда создание элемента будет завершено) и использовать идентификаторсозданного элемента после завершения обновления.

Есть ли лучший способ сделать это?

Буду очень признателен за любой совет.

Ответы [ 5 ]

0 голосов
/ 23 февраля 2019
      // in your service 

        items: Item[]=[];
        $$items=new BehaviorSubject(this.items);


           // creates an Item and returns the ID of the created Item
            createItem(item: Item): Observable<ItemId> {
             return this.http.post<ItemId>('some_api_url', item)
           }

            // returns all Items
      getAllItems(): Observable<Item[]> {
     return this.http.get<Item[]>('some_api_url').pipe(map(response=>{
      return {//format response here//}

}).subscribe(result=>{
this.items=result;
     this.$$items.next(this.items);
        })
       }

       returnItemsAsObs(){
        return this.$$items.asObservable();

        }

         //in your component
          items:Item[]
            $$items: Subscription

         ngOninit(){
         this.service.getAllItems()
         this.$items=this.service.returnItemsAsObs().subscribe(items=>{
         this.items=items;
         return this.items;

      })


    onCreateItem(item){
    return this.service.createItem(item).subscribe(item=>{
    if(item.length<0){
    //call other service for itemid manipulation
    this.service.getAllItems();


     }

    })


    }


    }
0 голосов
/ 23 февраля 2019

После еще нескольких копаний в операторах RxJS я подумал, что самое чистое решение - просто объединить concat с toArray:

// import { concat } from 'rxjs';
// import { toArray } from 'rxjs/operators';

concat(
  this.itemService.createItem(item),
  this.itemService.getAllItems())
    .pipe(toArray())
    .subscribe((result: [ItemId, Item[]]) => {
      // result[0] is the ItemId
      // result[1] is the Item[]
    });
0 голосов
/ 23 февраля 2019

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

// I use a function here for the purpose of making the code more readable
const itemsWithNew = (newItemId) => this.itemService.getAllItems()
                                        .pipe(map(items => ({items,newItemId})));
this.itemService.createItem(item)
    .pipe(
      switchMap(itemsWithNew)
    ).subscribe(({items, newItemId})=> {
      this.items = items;

      // newItemId is the new value
    });
0 голосов
/ 23 февраля 2019

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

this.itemService.createItem(item).pipe(
      switchMap(
        () => this.itemService.getAllItems(),
        (createdId, items) => {
           // can do some stuff here with both outer and inner values
           return { createdId, items };
        },
      ),
    ).subscribe({ createdId, allItems }) => {
      this.items = allItems;
    });
0 голосов
/ 23 февраля 2019

Вы можете использовать оператор concatMap.Попробуйте сначала создать элемент, затем дождитесь выполнения с помощью оператора concatMap.Возьмите результат выполнения в allItems наблюдаемую и затем объедините результаты, используя оператор map.В подписке у вас будет объект createdItem и allItems

const createdItem = this.itemService.createItem(item);
const allItems = this.itemService.getAllItems();

createdItem
  .pipe(
    concatMap(item =>
              allItems.pipe(
                map(items => ({
                  createdItem: item,
                  items
                })
              )
    )
  )
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...