最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Passing down values from multiple Observables - Stack Overflow

programmeradmin6浏览0评论

In my Angular service i have the following methods:

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

In my template i'm showing the items in a list.

I would like to be able to create a new item and then re-load the list (to include the newly created item), so i've implemented the following:

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

This seemingly works fine, but in the end i would like to do some processing with the createdId as well:

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

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

So i've came up with the following:

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

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

But having to use bineLatest inside the switchMap and explicitly make createdId an Observable makes me wonder if this is a good solution.

So basically i would like to create and item, update the list (when the item creation is finished) and use the ID of the created item when the update is finished.

Is there a better way to do this?

I'd really appreciate any advice.

In my Angular service i have the following methods:

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

In my template i'm showing the items in a list.

I would like to be able to create a new item and then re-load the list (to include the newly created item), so i've implemented the following:

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

This seemingly works fine, but in the end i would like to do some processing with the createdId as well:

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

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

So i've came up with the following:

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

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

But having to use bineLatest inside the switchMap and explicitly make createdId an Observable makes me wonder if this is a good solution.

So basically i would like to create and item, update the list (when the item creation is finished) and use the ID of the created item when the update is finished.

Is there a better way to do this?

I'd really appreciate any advice.

Share Improve this question asked Feb 23, 2019 at 11:23 justanoobjustanoob 1,80713 silver badges33 bronze badges 1
  • I remend changing this a bit and returning a subject, or better yet a behavior subject. That way you call next value of the service observable and return the subject as an observable. Any subscribers will get the new variable. – Pari Baker Commented Feb 23, 2019 at 18:39
Add a ment  | 

5 Answers 5

Reset to default 3

After some more digging into RxJS operators i figured the cleanest solution might be to simply bine concat with 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[]
    });

You can use the concatMap operator. Try to first create the item, then wait for the execution using the concatMap operator. Take the output of the execution in the allItems observable and then merge the results using a map operator. In the subscribe, you will have an object of createdItem and allItems

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

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

You need to pipe the result of the inner observable in order to further pass down the value emited by the source. You can do this as follows:

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

Alternatively, switchmap also accepts a second result callback for processing both the outer value and inner value together.

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

  1. 暂无评论