Deniz Bayar
Deniz Bayar

Reputation: 169

Angular 5 Rxjs Service returns data "undefined" in NgOnInit

I am trying to pass two data(number) from one component to another component. I can send datas and get succesfully this data on second component which I wanted to use them. However when I wanted to use them in NgOnInit it seems that I can not use them. I will add my code. Is there any ideas about it ?

Here my service

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

    @Injectable()
    export class StreetviewService {

    public StreetviewLatSubject= new Subject<any>();
    public StreetviewLonSubject= new Subject<any>();

    constructor() { }

    sendLatToStreetview(latt){
    this.StreetviewLatSubject.next(latt);
    console.log("I have the LAT streetview data: "+latt);
    }

    }

here the first component

    import { Component, OnInit} from '@angular/core';
    import {StreetviewService} from '../../services/streetview.service';

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

    latt:number=0;

    constructor(public streetviewService:StreetviewService)
    {}

    // I am getting data from HTML selector

    onClickStreetview(lat){
    console.log(lat); 
    this.latt=lat;
    this.passStreetviewLat(this.latt);
    }

    passStreetviewLat(latt){
    this.streetviewService.sendLatToStreetview(latt);
    console.log("I have sent latt right now... "+latt);
    }

here is my second component

    import { Component, OnInit, ViewChild, Input, Inject, PLATFORM_ID, Output                         
    } from '@angular/core';
    import { MapsAPILoader } from '@agm/core';
    import { isPlatformBrowser } from '@angular/common';
    import {StreetviewService} from '../../services/streetview.service';
    import {DataService} from '../../services/data.service';

    @Component({
    selector: 'app-streetview',
    templateUrl: './streetview.component.html',
    styleUrls: ['./streetview.component.scss']
    })
    export class StreetviewComponent implements OnInit {
      @ViewChild('streetviewMap') streetviewMap: any;
      @ViewChild('streetviewPano') streetviewPano: any;
       public latt:number;
       public lonn:number;
       public lat:number;
       public lon:number;
      @Input() zoom: number = 11;
      @Input() heading: number = 34;
      @Input() pitch: number = 10;
      @Input() scrollwheel: boolean = false;
      newcenter:any=
      {lat:52.2296756,
        lon:21.012228700000037,
        zoom:14 }; 

      constructor( public streetviewService: StreetviewService,public                 
     dataService: DataService, @Inject(PLATFORM_ID) private platformId:         
     Object, private mapsAPILoader: MapsAPILoader ){

    this.streetviewService.StreetviewLatSubject.subscribe((receivedData)=>
    {this.latt=receivedData

    // Here we can see data !

    console.log("Right now we will see streetview Latitude: "+this.latt) })
      }

      ngOnInit() {

        console.log(this.latt) // Here shows that it is undefined !

        if(isPlatformBrowser(this.platformId)){
          this.mapsAPILoader.load().then(() => {
            let center = { lat:this.latt, lng: this.lonn };
            let map = new window['google'].maps.Map(this.streetviewMap.nativeElement, { center:center, zoom: this.zoom, scrollwheel: this.scrollwheel });
            let panorama = new window['google'].maps.StreetViewPanorama(
              this.streetviewPano.nativeElement, {
                position: center,
                pov: { heading: this.heading, pitch: this.pitch },
                scrollwheel: this.scrollwheel
              });
              map.setStreetView(panorama);
            });
          }


         }

    }

Upvotes: 0

Views: 823

Answers (1)

user6749601
user6749601

Reputation:

It's the typical problem with asynchronous requests. And your service subscription is an asynchronous request.

From the view of a timeline when a component loads, the constructor and ngOnInit get processed almost plesiochronously. So while the console.log() inside the service subscription is still waiting for the value to return, the console.log() inside ngOnInit has already fired. And at this time this.latt is still undefined.

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

      constructor(){
          this.streetviewService.StreetviewLatSubject.subscribe((receivedData)=>
      {
       this.latt=receivedData;
       console.log("I was received asynchronously: " + this.latt) })
      }

      ngOnInit() {
         console.log('I don't care when the streetviewService returns its value: ' + this.latt);
      }

The same would happen if you'd do this:

 ngOnInit(): void {   
    this.streetviewService.StreetviewLatSubject.subscribe((receivedData)=>
    {
       this.latt=receivedData;
       console.log("I was received asynchronously: " + this.latt) })
    }

    console.log('I don't care when the streetviewService returns its value: ' + this.latt);
}

So if you have to wait for the data to arrive before going on with your workflow, call the follow up method out of the service subscription, like this:

// inside constructor or ngOnInit
this.streetviewService.StreetviewLatSubject.subscribe((receivedData)=>
    {
       this.latt=receivedData;

       doSomething();
    }

...

private doSomething(): void {
   // do something with this.latt
}

Upvotes: 1

Related Questions