1

How do I use an observable from early stage of the chain (not the last one).

I have code like this:

deleteGroceryStoreAndItsOwner() {

    this.groceryStoreOwnerService.getGroceryStoreOwnerSummaries(this.city.uuid)
        .flatMap((groceryStoreOwnerSummaries: GroceryStoreOwnerSummary[]) => aircraftUserSummaries.filter(groceryStoreOwnerSummary=> groceryStoreOwnerSummary.user.gender == "Male"))
        .flatMap((groceryStoreOwnerSummary: GroceryStoreOwnerSummary) => this.groceryStoreService.searchGroceryStore(this.city.uuid, groceryStoreOwnerSummary.user.uuid))
        .flatMap((groceryStoreSummary: GroceryStoreSummary) => this.groceryStoreService.getGroceryStore(groceryStoreSummary.uuid))
        .flatMap((groceryStore: GroceryStore) => this.groceryStoreService.deleteGroceryStore(groceryStore))
        .flatMap((groceryStoreOwnerSummary: GroceryStoreOwnerSummary) => this.groceryStoreOwnerService.getGroceryStoreOwner(groceryStoreOwnerSummary)) // here is where i have the problem: how can i use the observable from early stage of the chain?
        .flatMap((groceryStoreOwner: GroceryStoreOwner) => this.groceryStoreOwnerService.deleteGroceryStoreOnwer(groceryStoreOwner))
        .subscribe(() => {
            console.log("deleted grocery store")
            console.log("deleted grocery store owner")
        })
};

after I deleted the grocery store in the 4th flat map, I need to delete the grocery store owner, and this is from the second flatmap.

notes:

  1. each delete method (deleteGroceryStore and deleteGroceryStoreOnwer) returns an Observable.
  2. My app's angular version does not support pipe, so please don't give answers with .pipe.

Update: March 10 2022 I modified my code like this but for some reason the code in the map is not getting executed, any idea why?

deleteGroceryStoreAndItsOwner() {
    this.groceryStoreOwnerService.getGroceryStoreOwnerSummaries(this.city.uuid)
        .flatMap((groceryStoreOwnerSummaries: GroceryStoreOwnerSummary[]) => aircraftUserSummaries
            .filter(groceryStoreOwnerSummary => groceryStoreOwnerSummary.user.gender == "Male"))
        .map((groceryStoreOwnerSummary: GroceryStoreOwnerSummary) => {
            this.groceryStoreService.searchGroceryStore(this.city.uuid, groceryStoreOwnerSummary.user.uuid)
                .flatMap((groceryStoreSummary: GroceryStoreSummary) => this.groceryStoreService.getGroceryStore(groceryStoreSummary.uuid))
                .flatMap((groceryStore: GroceryStore) => this.groceryStoreService.deleteGroceryStore(groceryStore))
            this.groceryStoreOwnerService.getGroceryStoreOwner(groceryStoreOwnerSummary)
                .flatMap((groceryStoreOwner: GroceryStoreOwner) => this.groceryStoreOwnerService.deleteGroceryStoreOnwer(groceryStoreOwner))
        })
        .subscribe(() => {
            console.log("deleted grocery store")
            console.log("deleted grocery store owner")
        })
};

I also tried this but that still did not work:

deleteGroceryStoreAndItsOwner() {
    this.groceryStoreOwnerService.getGroceryStoreOwnerSummaries(this.city.uuid)
        .flatMap((groceryStoreOwnerSummaries: GroceryStoreOwnerSummary[]) => aircraftUserSummaries
            .filter(groceryStoreOwnerSummary => groceryStoreOwnerSummary.user.gender == "Male")
            .map((groceryStoreOwnerSummary: GroceryStoreOwnerSummary) => {
                this.groceryStoreService.searchGroceryStore(this.city.uuid, groceryStoreOwnerSummary.user.uuid)
                    .flatMap((groceryStoreSummary: GroceryStoreSummary) => this.groceryStoreService.getGroceryStore(groceryStoreSummary.uuid))
                    .flatMap((groceryStore: GroceryStore) => this.groceryStoreService.deleteGroceryStore(groceryStore))
                this.groceryStoreOwnerService.getGroceryStoreOwner(groceryStoreOwnerSummary)
                    .flatMap((groceryStoreOwner: GroceryStoreOwner) => this.groceryStoreOwnerService.deleteGroceryStoreOnwer(groceryStoreOwner))
            }))
        .subscribe(() => {
            console.log("deleted grocery store")
            console.log("deleted grocery store owner")
        })
};
STH
  • 73
  • 6
  • I think you will need to nest the flatMaps in order to have a reference to the events higher up the chain. Check out [this answer](https://stackoverflow.com/a/63462962/1858357) to ["How to pass results between chained observables"](https://stackoverflow.com/q/63386585/1858357). Note: the code sample in the answer is for a newer version of RxJS, but the concept is the same. – BizzyBob Mar 09 '22 at 22:34
  • @BizzyBob after looking at the referenced answer, I am still not sure how to do that without having pipe. Can you please give an example without using pipe? – STH Mar 10 '22 at 05:09
  • The answer below shows example without using pipe. – BizzyBob Mar 10 '22 at 14:11
  • @BizzyBob, thank you I made an update to my code (see above), do you know why the lines in the map are not getting executed. searchGroceryStore, getGroceryStore, deleteGroceryStore, deleteGroceryStoreOnwer are all observables. – STH Mar 10 '22 at 17:23
  • in `map` inside the curly braces, you are not returning anything! Also, if `searchGroceryStore` is observable, you probably need `flatMap` instead of plain `map`. – BizzyBob Mar 10 '22 at 23:34

1 Answers1

0

You can accomplish this by nesting the operators instead of chaining them.

Here's a simplified example that WON'T work:

const teamSummary = userId
  .flatMap(userId  => getUser(userId))
  .flatMap(user    => getManager(user.managerId))
  .flatMap(manager => getDirectReports(manager.id))
  .map(reports     => buildSummary(user, manager, reports)) 
;                  // cannot find name 'user' / 'manager'

When we nest the operators, all the parameters are accessible inside the map:

const teamSummary = userId
  .flatMap(userId => getUser(userId)
    .flatMap(user => getManager(user.managerId)
      .flatMap(manager => getDirectReports(manager.id)
        .map(reports => buildSummary(user, manager, reports))
      )
    )
  );

FWIW, here's a little StackBlitz

BizzyBob
  • 12,309
  • 4
  • 27
  • 51