1

I am working on a project where parents and children need to communicate via service. Following this article in the official documentation I am not able to make it work.

This is the service I created:

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';

@Injectable()
export class CommonService {
    private _propertyChangeAnnouncedSource = new Subject<string>();
    propertyChangeAnnounced$ = this._propertyChangeAnnouncedSource.asObservable();

    public announcePropertyChange(data: string) {
        this._propertyChangeAnnouncedSource.next(data);
    }
}

In the parent component, I import all I need:

@Component({
    selector: 'app-parent',
    templateUrl: './parent.component.html',
    styleUrls: ['./parent.component.scss'],
    providers: [CommonService]
})
export class ParentComponent implements OnInit {

    constructor(private _commonService: CommonService) {

    }

    tellChild(data): void {
        this._commonService.announcePropertyChange(data);
    }

}

This is the child's code:

@Component({
    selector: 'app-child',
    templateUrl: './child.component.html',
    styleUrls: ['./child.component.scss']
})
export class ChildComponent implements OnInit, OnDestroy {
    private subscription: Subscription;

    constructor(private _commonService: CommonService) {
        this.subscription = this._commonService.propertyChangeAnnounced$.subscribe(
            data => {
                console.log(data);
          });
    }
}

When I call the announcePropertyChange the child is not responding. Any suggestion?

Thanks!

relez
  • 750
  • 2
  • 13
  • 28

2 Answers2

2

There could be several problems:

  1. Check whether or not child and parent component have the same instance of the service. You could have provided CommonService several places thus parent and child might not share same instance of the class.

  2. How do you exactly execute tellChild() method? Maybe you execute the method when the parent component is initiated, thus new event is emitted by Observable, but child has not yet created and has not subscribed to Observable, it skips the event.

Possible solutions:

  • If problem 2 is your case then I suggest you to update your CommonService to use BehaviorSubject instead of Subject. private _propertyChangeAnnouncedSource = new BehaviorSubject<string>(null); This way no matter what time someone subscribes to the Observable they will get the latest value and continue monitoring further changes. If you want to avoid initial null value due to BehaviorSubject, I suggest you to modify Observable like so: propertyChangeAnnounced$ = this._propertyChangeAnnouncedSource.asObservable() .pipe(filter(x => x !== null));

This is it for now, lets hear from you about these 2 and I will update my response later if there is still the problem.

Goga Koreli
  • 2,807
  • 1
  • 12
  • 31
  • Hi there, thanks for your answer, the service is working but the problem is that the child component renders when a call to a REST API is called and bring back some information I need to send to the child component. The problem now is that somehow I need to know if the child's component is rendered. – relez Jul 12 '19 at 15:23
  • @relez Have a look at possible solution for number 2. What do you think? – Goga Koreli Jul 12 '19 at 15:55
  • 1
    Thanks for your answer, I have it working perfectly like this: in the CommonService, I have 2 Subject, one for send the information the child needs once the call is done in the father's side, its called PropertyChangeAnnounced. The second subject is to know when the child was initialized, and its called ChildRenderedAnnounce, which will tell the father he is ready to receive the information, in that case I will perform tellChild() method, which is inside a subscription in the father's constructor. What is the difference between Subject and BehaviorSubject? Thanks! – relez Jul 12 '19 at 18:29
  • Have a look at difference between Subject and BehaviorSubject at https://stackoverflow.com/questions/43348463/what-is-the-difference-between-subject-and-behaviorsubject – Goga Koreli Jul 13 '19 at 12:26
0

Seems like there is a typo in your child component constructor.

private subscription;
  constructor(private _commonService: CommonService) {
        this.subscription = this._commonService.propertyChangeAnnounced$.subscribe(
            data => {
                console.log(data,'from child');
          });
    }

This works for me. Also Please show how is the tellChild invoked in your code:

<button (click)="tellChild('TestData')">Tell child</button>

Check the working Demo Here:

nircraft
  • 8,242
  • 5
  • 30
  • 46
  • The typo was a mistake copying from the original code, tellchild is invoked in the propertyChange event, this is a where the user could switch properties. – relez Jul 11 '19 at 21:48