1
votes

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

1
Shouldn't the Injectable decorator be like: @Injectable() ?? - Ashish Ranjan
@AshishRanjan yeah sorry i will update that now - blueprintchris
@AshishRanjan still showing undefined - blueprintchris
console.log(this.selectedPlan); under the subscription - Ashish Ranjan
RxJS is async so your assigning might occurs after the console.log - JEY

1 Answers

1
votes

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.