Add elements to rxjs BehaviorSubject or Subject of an array in Angular2+

无人久伴 提交于 2021-01-28 08:11:52

问题


I was reading up on how to share data between unrelated components in Angular from the "Unrelated Components: Sharing Data with a Service" section of the tutorial here.

I see how this example works for the string they are trying to share across their components, but my data type is a little more complex:

Namely, I think my BehaviorSubject should look like this:

private currentPopulationSource: BehaviorSubject<Population> = new BehaviorSubject<Population>(new Population(new Array<Organism>()));

My population model is simply a container for an array of Organisms:

import { Organism } from './organism.model';

export class Population {
  private individuals: any;
  constructor(individuals: Organism[]){
     this.individuals = individuals;
  }

  getIndividuals(){
    return this.individuals;
  }
}

I have an instance of Organism, let's call it organism1.

I'd like to add it to the individuals array wrapped in the Population model, and I'd like for multiple unrelated components to subscribe to the population BehaviorSubject (I currently have private currentPopulation = this.currentPopulationSource.asObservable(); in my PopulationManagerService right after my declaration of currentPopulationSource, as I saw in the tutorial).

It's unclear to me what the syntax would be to add organism1 to my currentPopulationSource (.next() doesn't seem to make sense here).

Perhaps BehaviorSubject isn't the most appropriate choice to make here if I want an ever-growing array to be the thing emitted? If there is a better option (ReplaySubject?), I don't quite know how to implement it.

My population manager service:

import { Injectable } from '@angular/core';
import { Organism } from './organism.model';
import { Population } from './population.model';
import { BehaviorSubject } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class PopulationManagerService {
  private currentPopulationSource: BehaviorSubject<Population> = new BehaviorSubject<Population>(new Population(new Array<Organism>()));
  currentPopulation = this.currentPopulationSource.asObservable();
  constructor() { }

  addOrganismToPopulation(organism: Organism){
    this.currentPopulationSource.next(new Population(new Array<Organism>(organism))); //This does not work
    // this.currentPopulation.getIndividuals().push(organism); //This did not work either, because currentPopulation is of type Observable<Population> rather than of type Population
  }
}

In my component:

let testIndividual: Organism = this.individualGenService.makeIndividual("green", "blue");
    this.popManager.addOrganismToPopulation(testIndividual);
    this.popManager.currentPopulation.subscribe(results =>{
      console.log(results.getIndividuals()); //returns undefined
    });

This is returning undefined currently.

Very grateful for any help with this issue.


回答1:


If I understand correctly, you want to add a new organism to the list of organisms that is inside a population object. This while using a behavior subject.

In your example you could do the following.

addOrganismToPopulation(organism: Organism){
    this.currentPopulationSource
        .pipe(take(1))
        .subscribe((population: Population) => {
            this.currentPopulationSource.next(
                new Population([...population.getIndividuals(), organism]))
            )
        });
  }

So what are we doing here. To add a new organism to the current population we need to know the list of organisms. So we subscribe to the observable that holds the population. Inside the subscription we create a new instance of population. While creating the new instance we create an array of the already known organisms together with the new one. Then we next the new/updated population onto the stream.

Notice that I only take one value of the stream, take(1). This is because the moment we want to calculate the new list of organisms we only need the current population. This as well prevents an unwanted memory leak. The take operator unsubscribes from the stream the moment one event has passed.

Whether the behavior subject is a good choice for your use case is hard to say with a minimum of information.



来源:https://stackoverflow.com/questions/52391619/add-elements-to-rxjs-behaviorsubject-or-subject-of-an-array-in-angular2

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!