0

I load my data like this in a Service:

employees: Observable<Employee[]>;

private loadEmployees() {
    this.employees = this.db.collection('Employees').snapshotChanges().pipe(
        map(changes => changes.map(a => {
            const employee = a.payload.doc.data() as Employee;
            employee.id = a.payload.doc.id;

            return employee;
        }))
    )
}

I want to subscribe to the employees Oberservable in multiple Components. Like this:

this.businessService.employees.subscribe(
  (employees) => {
    this.employees = employees;
  }
);

But It only works the first time. When I navigate to another component and do the same again it doesn't work. How can I subscribe to an Oberservable multiple times?

Or is the best way to subscribe directly in my service like this:

employees: Employee[];

private loadEmployees() {
    this.db.collection('Employees').snapshotChanges().pipe(
        map(changes => changes.map(a => {
            const employee = a.payload.doc.data() as Employee;
            employee.id = a.payload.doc.id;

            return employee;
        }))
    ).subscribe(
        employees => {
            this.employees = employees;
        }
    );
}

And then access the employee Array in my components. The problem is that I won't get notified in my components when the employees are loaded/changed. So I would need to have a EventEmitter that I fire once employees changes and and subscribe to in my components.

Jonas
  • 7,089
  • 15
  • 49
  • 110

2 Answers2

1

If you need to share data across more components, it is better to load the data from the observable once, and make it available to the other components using a service for example. In this way you are minimizing the interaction between components in your application and the outside world (the observable) and making the application more self-contained.

NiVeR
  • 9,644
  • 4
  • 30
  • 35
1

You can declare your employees as BehaviorSubject<Employee[]> instead. And whenever your employees change, you can then call the next method on this.employees which is a BehaviorSubject<Employee[]>. That way, you'll be able to get the changes in other components as well as soon as there's a change in this service's employees.

employees: BehaviorSubject<Employee[]> = new BehaviorSubject<Employee[]>(null);

private loadEmployees() {
    this.db.collection('Employees').snapshotChanges().pipe(
        map(changes => changes.map(a => {
            const employee = a.payload.doc.data() as Employee;
            employee.id = a.payload.doc.id;

            return employee;
        }))
    ).subscribe(
        employees => this.employees.next(employees);
    );
}

Whichever component does this:

this.businessService.employees.subscribe(employees => this.employees = employees);

will get the recently updated employees list.

SiddAjmera
  • 38,129
  • 5
  • 72
  • 110
  • Thanks, so this is similar to the 2nd way I described, just instead of EventEmitter I use BehaviourSubject? Is there actually a difference between `EventEmitter` and `BehaviourSubject`? I will try it this way. – Jonas Sep 05 '18 at 19:15
  • `BehaviorSubjects` are preferred over EventEmitters. Find read this thread out for the reason. https://stackoverflow.com/a/35568924/2622292 – SiddAjmera Sep 05 '18 at 19:18