-1

My page contains two components, parent and child.

In the child I am receiving data from the server, and I save this data in a service. I want to execute a function in the parent only when the data in the service is not null, because I am using this data in the parent function.

How can I be sure that the data is already in the service before I execute the function in the parent?

Of course I want to execute the function while the page loads, as soon as possible, and I prefer to not use setTimeout function.

For example:

//child
this.jsonService.getData().subscribe(res => {
  this.CommonService.userDetails = res;    
} 
//service
@Injectable()
export class CommonService {
public userDetails: any;
}
//parent

// execute only when the this.CommonService.userDetails != null
doSomething(){ 
 alert(this.CommonService.userDetails)
}
jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
levi
  • 1,077
  • 2
  • 11
  • 24
  • 1
    Expose an observable from the service that sends an event when the value of userDetails is set. Then the parent just subscribes to that. – jonrsharpe Jun 20 '18 at 06:57
  • i am not sure what do you mean. you can attach some code? thanks! – levi Jun 20 '18 at 07:27
  • That's what the code in the answer already provided does. I'd recommend reading up on observables and RxJS, they're pretty central in Angular. – jonrsharpe Jun 20 '18 at 07:30

1 Answers1

2

Edited answer: As stated by @jonrsharpe and in the documentation about Component Interaction, it's better to use Subject rather than EventEmitter.

Here is the updated code for the service:

// Service
@Injectable()
export class CommonService {
    private userDetailsReceivedSource = new Subject<any>();

    userDetailsReceived$ = this.userDetailsReceivedSource.asObservable();

    private userDetailsData: any;

    receiveUserDetails(data: any) {
        this.userDetailsData = data;
        this.userDetailsReceivedSource.next(data);
    }
}

Here is the code for the child component using receiveUserDetails:

// Child
this.jsonService.getData().subscribe(res => {
    this.CommonService.receiveUserDetails(res);    
} 

Here is the updated code for the parent component using userDetailsReceived$:

// Parent
constructor() {
    this.CommonService.userDetailsReceived$.subscribe(_ => this.doSomething());
}

Original answer:

In the service, you will need an EventEmitter to notify the parent component when the data is available.

The setter is used to emit the event when we receive the data from the child component.

// Service
@Injectable()
export class CommonService {
    public onUserDetailsReceived = new EventEmitter<any>();

    private userDetailsData: any;

    public get userDetails(): any {
        return this.userDetailsData
    }

    public set userDetails(data: any) {
        this.userDetailsData = data;
        onUserDetailsReceived.emit();
    }
}

In the parent component, you will have to subscribe to the EventEmitter to be notified.

// Parent
constructor() {
    this.CommonService.onUserDetailsReceived.subscribe(_ => this.doSomething());
}
ADreNaLiNe-DJ
  • 4,787
  • 3
  • 26
  • 35
  • are you sure about this syntax? "public get userDetails" it's not compile for me. And I did not quite understand, how the userDetails refer to the EventEmitter. thanks you! – levi Jun 20 '18 at 07:19
  • @levi Sorry, some parenthesis was missing: answer edited. – ADreNaLiNe-DJ Jun 20 '18 at 07:26
  • You shouldn't use EventEmitters for purposes other than component @Outputs; see e.g. https://stackoverflow.com/questions/36076700/what-is-the-proper-use-of-an-eventemitter#36076701. Use a proper subject/observable instead, if you aren't sure how I've written about it e.g. here: https://blog.jonrshar.pe/2017/Apr/09/async-angular-data.html. – jonrsharpe Jun 20 '18 at 07:29
  • @jonrsharpe Thanks for pointing this out. I've updated the answer. – ADreNaLiNe-DJ Jun 20 '18 at 07:38