Reputation: 12121
I have a small shared Angular service which looks as follows:
import {Injectable} from '@angular/core';
import {BehaviorSubject, Observable} from 'rxjs/Rx';
@Injectable()
export class SidebarService {
private _isOpen: BehaviorSubject<boolean> = new BehaviorSubject(false);
constructor() {
this._isOpen.subscribe(val => {
console.log(`isOpen: ${val}`);
});
}
public get isOpen() {
return this._isOpen.asObservable();
}
toggle() {
this._isOpen.next(!this._isOpen.getValue());
}
}
And I would like to bind the .isOpen
property to an element in a view. I am currently using the following snippet to attempt binding in the view:
<p>Sidebar State: {{sidebarService?.isOpen | async}}</p>
The property is binding initially, however not responding to successive changes. What I want is for Sidebar State: to update when the sidebar toggle() method is called inside SidebarService.
Any ideas?
Upvotes: 3
Views: 6035
Reputation: 12121
The issue was caused by having multiple instances of the SidebarService running.
I fixed the issue by moving the declarations for providers in the @Component decorators from two components that shared the SidebarService to app.module.ts like so:
@NgModule({
declarations: [
// ...
SidebarComponent,
// ...
],
imports: [ /* ... */ ])
],
// Line below was duplicated in two components,
// causing multiple instances...
providers: [SidebarService], // <--
bootstrap: [AppComponent]
})
This means that my binding was observing changes on a whole different instance of an Observable all together.
I also found that the .asObservable() call is entirely unnecessary, so the resulting SidebarService now looks as follows:
import {Injectable} from '@angular/core';
import {BehaviorSubject, Observable} from 'rxjs/Rx';
@Injectable()
export class SidebarService {
private _isOpen: BehaviorSubject<boolean>;
constructor() {
this._isOpen = new BehaviorSubject(true);
}
public get isOpen() {
return this._isOpen;
}
toggle() {
this._isOpen.next(!this._isOpen.getValue());
}
}
Upvotes: 6