BehaviorSubject any to any communication

Use a BehaviorSubject to enable any to any component comunication.

Motivation and implementation

Enabling the main photo refresh in the navbar is not possible using the classic @Output and EventEmitter because the two components are too far away in the hierarchy.

A BehaviorSubject is both an Observer and an Observable and it only remembers the last publication.

In this case we will add a BehaviorSubject to auth.service.ts and in nav.component.ts we will subscribe to it. Meanwhile in photo-editor.component.ts we will remove the mainPhotoChanged EventEmitter and call the auth.service.ts to update the photo.


Open auth.service.ts add a new property for the BehaviorSubject and a public Observable.

Add a default photo image in the assets folder.

private mainPhotoUrl = new BehaviorSubject<string>('../../assets/user.png');
currentPhotoUrl = this.mainPhotoUrl.asObservable();

Remove the getUser function.

Add a new function to be called by photo-editor

changeMemberPhoto(photoUrl: string) {;
  this.user.profilePhotoUrl = photoUrl;
  localStorage.setItem(LOCALSTORAGE_USER_KEY, JSON.stringify(this.user));

Refactor login and loadFromLocalStorage

login(model: any) {
  return this.http
    .post(this.baseUrl + 'login', model, this.httpOptions())
      map((response: any) => {
        if (response) {
          const token = response.tokenString;
          localStorage.setItem(LOCALSTORAGE_TOKEN_KEY, token);
          this.userToken = token;
          this.decodedToken = this.jwt.decodeToken(token);

          this.user = response.user;
          localStorage.setItem(LOCALSTORAGE_USER_KEY, JSON.stringify(this.user));
loadFromLocalStorage() {
  const token = localStorage.getItem(LOCALSTORAGE_TOKEN_KEY);
  if (token) {
    this.userToken = token;
    this.decodedToken = this.jwt.decodeToken(token);
  const user = localStorage.getItem(LOCALSTORAGE_USER_KEY);
  if (user) {
    this.user = JSON.parse(user);;

Open nav.component.ts and add a new property to store the url and subscribe to the BehaviorSubject Observer. Remove the method getPhotoUrl.

photoUrl: string;
ngOnInit() {
  this.authService.currentPhotoUrl.subscribe(next => this.photoUrl = next);

Open nav.component.html and update the markup

<img src="{{photoUrl}}" alt="{{getUsername()}}">


Open member-edit.component.ts and remove the method reloadMainPhoto and the binding to mainPhotoChanged in html.

<app-photo-editor [photos]=""></app-photo-editor>

Subscribe to the BehaviorSubject Observer.

ngOnInit() { => {
    this.user = data['user'];

  this.authService.currentPhotoUrl.subscribe(next => { this.user.profilePhotoUrl = next; });


Open photo-editor.component.ts and remove the @Output property mainPhotoChanged.

Then in the function setMainPhoto instead of emitting the event we call the authService method changeMemberPhoto

setMainPhoto(photo: Photo) {
      () => {
        const oldMain = _.findWhere(, { isMain: true });
        oldMain.isMain = false;
        photo.isMain = true;
        this.mainPhoto = photo;
      error => {

Test the application:

  • Setting a main photo will immediately change the profile photo in the profile editor and in the navbar.
  • Refreshing the page will load the last saved photo from localStorage.