Share operator with nested observables

72 views Asked by At

I create a game module that is responsible for loading the player's buildings, and then modifying the fetched objects to an extended building class containing an additional field - remainingTime, informing how many seconds are left to complete the upgrading lvl of buildings (this field is refreshed every second).

buildings -> buildingsWithDiff -> buildingsWithTimer

  1. Loading buildings
  2. Map buildings to buildingsWithDiff to know the difference between the date on which the timer starts date and the end upgrading date
  3. Map buildingsWithDiff to buildingsWithTimer which subtracts the number of ticks from the resulting difference
class Building {
  name: string;
  lvl: number;
  endDate: Date; // date of upgrading of the building
}

class BuildingWithDiff extends Building {
  diffTime: number; // difference of seconds between the currentDate and the endDate;
}

class BuildingWithTimer extends BuildingWithDiff {
  remainingTime: number; // seconds left to complete upgrading a building
}

/* ------------- */

const getBuildings$ = (store: Store): Observable<Building[]> => {
  const buildings$: Observable<Building[]> = store.select(
    (appState: AppState) => appState.buildings
  ); // source
  return buildings$;
};

const getBuildingsWithTimers$ = (
  store: Store
): Observable<BuildingWithTimer[]> => {
  const buildings$: Observable<Building[]> = getBuildings$(store);

  const buildingsWithDiff$: Observable<BuildingWithDiff[]> = buildings$.pipe(
    map((buildings) =>
      buildings.map((building) => {
        const currentDate: Date = new Date();
        const diffTime: number =
          Math.ceil(
            building.endDate.getTime() - currentDate.getTime()
          ) / 1000;

        return {
          ...building,
          diffTime,
        };
      })
    )
  );

  const buildingsWithTimer$: Observable<BuildingWithTimer[]> = buildingsWithDiff$.pipe(
    switchMap((buildingsWithDiff) =>
      timer(0, 1000).pipe(
        map((tick: number) =>
          buildingsWithDiff.map((buildingWithDiff) => {
            const remainingTime: number = buildingWithDiff.diffTime - tick;

            return {
              ...buildingWithDiff,
              remainingTime,
            };
          })
        )
      ),
      // share()? - it doesn't work :(
    )
  );

  return buildingsWithTimer$;
};

Multicasting nested timers - How to?

Subscribing to the selector above generates errors because there are several observers and not all of them run at the same time. Adding the share operator doesn't work. Where could the problem be?

There are two places where this is subscribed:

  • trigger- a function that is called in ngxsOnInit (waits for remainingTime <= 0 to dispatch the appropriate action)
  • building component - angular component which displays the remaining time

The application works fine when I turn it on on the subpage where this component exists - both observers display the same tick value in the timer.

The problem is when I exit the subpage where the component was, because the trigger works all the time and the ticks are still counted but the component ends the subscription and when I want to return to the subpage, the ticks are counted from zero.

Ultimately, there are two different ticks.

0

There are 0 answers