1

Using Angular 5, I have 2 components and a shared service which I want to pass data through, from one component to another.

I subscribe to the variable in my receiving component's oninit and attempt to console.log the result but it is always showing as undefined.

The component which makes the initial service function call _quoteSummaryService.setSelectedPlan() is called via HTML button click selectPlan(), and the object that's passed into is not showing as undefined.

I can even console.log the object within the service function and it also isn't undefined. It's only undefined when I call console.log on the receiving components oninit function, after subscribing.

The variable selectedPlan is showing as undefined when inserted into the receiving components HTML as {{ selectedPlan? }}.

quote-summary.service.ts:

import { Injectable } from '@angular/core';
import { Subject }    from 'rxjs/Subject';
import { Quote } from '../models/quote-response.model';

@Injectable()
export class QuoteSummaryService {

    constructor(){}

    private _quoteSelectedPlanSource = new Subject<Quote>();
    public quoteSelectedPlan = this._quoteSelectedPlanSource.asObservable();

    setSelectedPlan(selectedPlan:Quote) {
        this._quoteSelectedPlanSource.next(selectedPlan);
    }
}

quote-select-plan.component.ts: (the component that makes the service call)

export class QuoteSelectPlanComponent implements OnInit {
  constructor(private _quoteSummaryService:QuoteSummaryService, private _router: Router) {}

  selectPlan(selectedPlan) {
    this._quoteSummaryService.setSelectedPlan(selectedPlan);
    if (selectedPlan !== undefined) {
      this._router.navigateByUrl('/quote/details/assumptions');
    }
  }
}

quote-summary.component.ts: (the component that subscribes to the variable but is showing as undefined)

export class QuoteSummaryComponent implements OnInit {
  constructor(private _quoteSummaryService:QuoteSummaryService) { }

  public selectedPlan: Quote;

  ngOnInit() {
    this._quoteSummaryService.quoteSelectedPlan.subscribe(plan => { this.selectedPlan = plan });
    console.log(this.selectedPlan) //showing as undefined
  }
}

I am a bit stumped now. Here is a list of things I have tried that haven't worked. I feel like I am missing something simple.

  • Changing the variable source in the service from type Subject to BehaviorSubject

  • Adding a Getter into the receiving component and trying to access the variable directly from the service.

  • Async pipe in the HTML

  • Basically everything mentioned in the answer in this question

  • Tried subscribing the the variable in the sending component to see if that would do anything

12
  • Shouldn't the Injectable decorator be like: @Injectable() ?? Commented Jun 6, 2018 at 11:42
  • @AshishRanjan yeah sorry i will update that now Commented Jun 6, 2018 at 11:43
  • @AshishRanjan still showing undefined Commented Jun 6, 2018 at 11:45
  • console.log(this.selectedPlan); under the subscription Commented Jun 6, 2018 at 11:47
  • RxJS is async so your assigning might occurs after the console.log Commented Jun 6, 2018 at 11:48

1 Answer 1

1

JavaScript and with it TypeScript is an async language. When you subscribe to something the current function flow continues, and the subscribed function will only be called once the observable emits. This is -after- the console.log.

Change your code to this, and you get what you expect:

ngOnInit() {
  this._quoteSummaryService.quoteSelectedPlan.subscribe(plan => { 
    this.selectedPlan = plan;
    console.log(this.selectedPlan);
  });
}

You can add additional console.log before and after the subscribe, you will see that those are logged before the subscribed function is called.

Even though an Observable could be sync, it's always better never to trust on this.

Sign up to request clarification or add additional context in comments.

8 Comments

but how come it won't appear in my HTML and complains its undefined??
@blueprintChris because it is undefined at the moment the HTML gets rendered for the first time. This happens also before the subscribed function gets called. To prevent any errors with possibly undefined objects, you have to use the safe navigation operator .? inside your template.
@blueprintChris you can see this in action if you also place a console.log inside the ngAfterViewInit hook. You will see that this is also called before it logs the this.selectedPlan. Which means at the time of initial rendering, the selectedPlan is still undefined
@blueprintChris fix what :)? I don't see an error message, or anything. Just a console.log at the wrong place
It's showing undefined in the HTML. Cannot access the variable in the HTML.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.