Vicky
Vicky

Reputation: 17375

Sharing data returned from rest call between sibling components in Angular 4

This is my main component:

import { Component, OnInit } from '@angular/core';
import { MyService } from '../my-service.service';
import { DataShareService } from '../data-share-service.service';

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

  private myCustomer: Object;

  constructor(private myService: MyService) { }

  ngOnInit() {    
    this.getMyCustomerProfile();
    console.log("In Home: " + JSON.stringify(this.myCustomer)); // this prints undefined - why ?

    // this.dataShareService.currentCustomer.subscribe(customer => this.customer = customer);
    // this.dataShareService.changeCustomer(this.customer);
  }

  private getMyCustomerProfile(){
    this.myService.getProfile()
    .subscribe(
      customer => {
          this.myCustomer = customer;
          console.log("In Home: " + JSON.stringify(this.myCustomer)); // this prints the returned json properly
      },
      error => {
          console.log("Error fetching user profile!");
      });

     console.log("In Home: " + JSON.stringify(this.myCustomer)); // this prints undefined - why ?    
  }
}

MyService getProfile method is a rest call:

getProfile(){
  return this.http.get(this.config.myUrl + 'mycustomer/', this.options).map((response: Response) => response.json());
 }

Question 1: Why does the console.log inside getMyCustomerProfile's subscribe method prints the returned object json correctly but the other two console.log prints undefined ?

Question 2: Also, how do I share the returned Object in above component with Sibling component (and not child component) using shared service ?

I tried below, but its not working.

Shared Service:

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

@Injectable()
export class DataShareService {

  private customerSource = new BehaviorSubject<Object>("default customer");
  currentCustomer = this.customerSource.asObservable();

  constructor() { }

  changeCustomer(customer: Object){
    console.log("In Service: "+customer);
    this.customerSource.next(customer);
  }
}

Sibling:

import { Component, OnInit } from '@angular/core';
import { DataShareService } from '../data-share-service.service';

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

  private myCustomer: Object;

  constructor(private dataShareService: DataShareService) { }

  ngOnInit() {
    this.dataShareService.currentCustomer.subscribe(customer => this.myCustomer = customer);
  }
}

The HTML Template for both HomeComponent and SiblingComponent is printing a property from the returned object:

Welcome {{myCustomer?.name}}

This prints correctly in HomeComponent but not in SiblingComponent. Meaning the data is not getting shared. I am not sure what am I doing wrong.

Thanks for reading!

Upvotes: 0

Views: 365

Answers (2)

Vicky
Vicky

Reputation: 17375

Thanks to Martin for the inputs.

Updating my getMyCustomerProfile method to following worked:

 private getMyCustomerProfile(){
    this.myService.getProfile()
    .subscribe(
      customer => {
          this.dataShareService.changeCustomer(customer);
      },
      error => {
          console.log("Error fetching user profile!");
      });
  }

And subscribing the same in both Sibling and main component with the following line:

this.dataShareService.currentCustomer.subscribe(customer => this.customer = customer);

Upvotes: 0

martin
martin

Reputation: 96889

  1. It's all asynchronous. When you use console.log outside subscribe (or basically outside the operator chain) it'll be called before any value is emitted and therefore it's undefined.

  2. Just assign the value into a property in the service class:

    .subscribe(customer => this.myService.myCustomer = customer)
    

    If you need the sibling components to be able to react when the myCustomer changes asynchronously make it a BehaviorSubject (or ReplaySubject(1) would in this case do the same).

    .subscribe(customer => this.myService.myCustomer.next(customer))
    

Upvotes: 1

Related Questions