michalte97
michalte97

Reputation: 53

Angular DI circular reference when subscribing

I have two questions.

There is a full code example provided here: STACKBLITZ EXAMPLE

I need some explanation whether I understand it the right way or not. There is a short code snippet from the example:

 this.userService.castUser.subscribe(user => {
      this.user = user
      console.log(this); // <this> keyword here
    });
  1. Does passing a callback function working on this in the subscribe method create a circular reference between the component and the service? Something like the registered callback function in the service subscribers array points to the component instance which has the service instance injected, and this service has the subscribers array where there is the callback function pointing to the component instance, and so on and so on.

  2. What is the actual benefit of subscribing to observable rather than the subject itself? Can't we make user public and subscribe to it rather than to castUser?

    private user = new BehaviorSubject<string>('john');
    castUser = this.user.asObservable();
    

Upvotes: 0

Views: 164

Answers (1)

Fabian Strathaus
Fabian Strathaus

Reputation: 3570

  1. using this in an arrow function does reflect the actual this element during instantiation of this function. In your case this does reflect the component the subscription function was defined in.
  2. The actual benefit is managing complexity. Defining user as public would result in potentially multiple places in your application, where this variable can be changed. If you are the only one working on a codebase, this is rather fine. If you have multiple developers it is harder to prevent. To ensure that variables cannot be changed from another place as intended, I would actually encourage you to use the following approach
private readonly user = new BehaviorSubject<string>('john');
get castUser() {
  return this.user.asObservable();
}

Update after feedback from comment If you want to also perform some operations in the service, you should use rxjs operators in order to do this. I assume you want to perform some "sideeffect" like accessing properties from your service. In order to do this, you should use tap operator:

private readonly user = new BehaviorSubject<string>('john');
get castUser() {
  return this.user.asObservable().pipe(tap(user => {this.variableFromMyService = user}));
}

Another update after comment you can achieve binding the service as this to the function by removing the arrow declaration and binding the service to this function. Nevertheless I can't think of a reasonable scenario for this. The code below should work nevertheless:

this.injectedService.subscribe(
(function() {
    console.log(this); //this will be the service
}).bind(this.injectedService))

Upvotes: 0

Related Questions