'one component not getting update when other component update from shared service with Observable Subject

I have 2 component, ProfileComponent and AvatarComponent with no direct relation between them

Profile Component is used under user module ( user.module.ts ) and avatar component is being used in main module ( app.module.ts ) where I display user full name and profile picture on right top side.

My requirement is Whenever user edit his/her profile ( first name or last name ) and hit save button. than avatar also getting updated with new first name and last name

I have followed this Component Communication approach from Angular Documentation

but my issue is that avatar is never being updated, even constructor is not being called from avatar.component.ts

angular version 4.3.4

following is the relevant code

Profile.component.ts

import { Component } from '@angular/core';
import { UserService } from '../user.service';

@Component({
    selector: 'app-profile',
    templateUrl: './profile.component.html'
})
export class ProfileComponent implements OnInit {

    constructor(private userService: UserService) { }

    announce() {
        console.log('announce called: ');
        let username = 'alpha beta';
        this.userService.announceUser(username);
    }
    // when click on save button on edit profile button
    updateProfile(userProfile) {
        this.userService.updateUserDetail(userProfile).subscribe(
            (data: any) => {
                this.announce();
            }
        );
    }
}

avatar.component.ts

import { Component, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs/Subscription';

import { UserService } from '../../../user/user.service';

@Component({
    selector: 'app-avatar',
    templateUrl: `<div>
    <img #avatar [title]="fullName" alt="profile-picture">
    <span>{{fullName}}</span>
    </div>`
})
export class AvatarComponent implements OnDestroy {
    fullName: string;
    subscription: Subscription;
    constructor(private userService: UserService) {
        this.getAvatar();
        this.subscription = userService.missionAnnounced$.subscribe(
            username => {
                console.log('subscribe it in constructor'); //never being called
                this.fullName = username;
            });
    }

    ngOnDestroy() {
        this.subscription.unsubscribe();
    }

    getAvatar() {
        this.userService.getUserDetail().subscribe(
            (data) => {
                this.fullName = `${data.firstName} ${data.lastName}`;
                this.userService.getProfilePicture().subscribe(
                    (image) => {
                        this.image.nativeElement.src = window.URL.createObjectURL(image);
                    }
                );
            }
        );
    }
}

user.service.js

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import 'rxjs/add/operator/map';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';

@Injectable()
export class UserService {

private missionAnnounceUsername = new Subject<string>();
missionAnnounced$ = this.missionAnnounceUsername.asObservable();
constructor(private httpClient: HttpClient) { }

announceUser(user: string) {
    console.log('announceUser: ', user);
    this.missionAnnounceUsername.next(user);
}

getUserDetail() {
    return this.httpClient.get(`/user/profile`).map((res) => res.item);
}

updateUserDetail(data) {
    return this.httpClient.put(`/user/profile`, data);
}

}



Solution 1:[1]

found the solution from this issue

"Do not register any provider twice as this will create two independent instances."

I have registered UserService in main module app.module.ts whereas it should be in providers metadata of parent component of avatar.component.ts which is layout.component.ts

  • removed UserService from app.module.ts providers metadata.
  • add UserService from layout.component.ts providers metadata.

as <app-avatar> is used in layout.component.html

everything is working fine now.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 diEcho