从多个Observable传递值

时间:2019-02-23 11:23:41

标签: javascript angular rxjs

在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并将createdId明确地设为Observable使我怀疑这是否是一个好的解决方案。

因此,基本上,我想创建并添加项目,更新列表(完成创建项目时),并在更新完成后使用已创建项目的ID。

有更好的方法吗?

我真的很感谢任何建议。

5 个答案:

答案 0 :(得分:2)

深入研究RxJS运算符后,我发现最干净的解决方案可能是将concattoArray组合在一起:

// 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[]
    });

答案 1 :(得分:1)

您可以使用concatMap运算符。 尝试首先创建该项目,然后使用concatMap运算符等待执行。在allItems中观察执行结果,然后使用map运算符合并结果。在订阅中,您将有一个对象createdItemallItems

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

createdItem
  .pipe(
    concatMap(item =>
              allItems.pipe(
                map(items => ({
                  createdItem: item,
                  items
                })
              )
    )
  )

答案 2 :(得分:1)

您需要通过管道传递内部可观察的结果,以便进一步传递源发出的值。您可以按照以下步骤进行操作:

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

答案 3 :(得分:-1)

或者,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;
    });

答案 4 :(得分:-1)

      // 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();


     }

    })


    }


    }