Shared service's method not called in NgOnInit while loading the component through router.navigate method

596 Views Asked by At

I have a detail component and child components overview and contact, I have used a shared service to share an array ImageMap which is updated by the detail after retrieving from a service on its initialization and subscribed and accessed by the children on their respective init methods. When i navigate to child components manually typing the address in address bar the the snippet in the ngOnInit of child component to set the array value from shared service gets loaded, whereas while navigating by router.navigate on click of buttons, apart from that portion in NgOnInit everything else gets loaded. Please help me on this. Where have i gone wrong ?

//Account detail component.html

<h3>You selected brand {{item_name}}</h3>
<p>
    <button (click)="showOver()" class="btn btn-primary">Overview</button>
    <button (click)="showCon()" class="btn btn-info">Contact</button>
</p>
<router-outlet></router-outlet>
<button (click)="gotoAccounts()" class="btn btn-warning">Back</button>

//Datashare Service.ts

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

@Injectable({
    providedIn: 'root'
})
export class DatashareService {

  private dataObs$ =  new Subject();



     getData() {
        return this.dataObs$;
                }

updateData(data) {
    this.dataObs$.next(data);
                  }

 constructor() { }
}

//Account Detail Component.ts

import { Component, OnInit} from '@angular/core';
import { ActivatedRoute,Router,ParamMap } from '@angular/router';
import { ImageFetchService } from '../image-fetch.service';
import { DatashareService } from '../datashare.service';

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

public item_id;
public item_name;
public imageMap;
public errorMsg;
constructor(private route: ActivatedRoute,private router:Router,private 
imageService: ImageFetchService,
private dataService: DatashareService) { }

ngOnInit() {

//let id = parseInt(this.route.snapshot.paramMap.get('id'));
//this.item_id=id;

this.route.paramMap.subscribe((params: ParamMap)=>
{
  let id = parseInt(params.get('id'));
  this.item_id=id;
  let sel_name = params.get('name');
  this.item_name=sel_name;
  console.log(this.item_id,this.item_name);
}  )

 this.imageService.getImages().subscribe(data =>{ this.imageMap=data;

 this.dataService.updateData(this.imageMap);},
                                              error => this.errorMsg=error);




 }



  showOver()
  {
               let sel_name= this.item_name?this.item_name:null;

                this.router.navigate(['overview',{"name":sel_name}],
                {relativeTo:this.route})


   }

   showCon()
   {
       let sel_name= this.item_name?this.item_name:null;

       this.router.navigate(['contact',{"name":sel_name}],
       {relativeTo:this.route})

   }
  }

//Account Overview Component.ts

import { Component, OnInit,Input,OnDestroy,NgZone } from '@angular/core';
import {NgbCarouselConfig} from '@ng-bootstrap/ng-bootstrap';
import {map} from 'rxjs/operators';
import {HttpClient} from '@angular/common/http';
import { ActivatedRoute,Router,ParamMap } from '@angular/router';
import { DatashareService } from '../datashare.service';
import { Subscription } from 'rxjs/Subscription';


@Component({
  selector: 'app-account-overview',
  templateUrl: './account-overview.component.html',
  styleUrls: ['./account-overview.component.css'],
  providers: [NgbCarouselConfig]
})
export class AccountOverviewComponent implements OnInit,OnDestroy {
private subscription: Subscription = new Subscription();
public imageArray;
 public imageMap;
 public errorMsg;
 public selected_name;
  constructor(config: NgbCarouselConfig, private _http: HttpClient
  ,private route:ActivatedRoute,private dataService: DatashareService
  ,private zone:NgZone) {
    // customize default values of carousels used by this component tree
    config.interval = 2000;
    config.keyboard = false;
    config.pauseOnHover = false;
  }

  ngOnInit() {

   this.route.paramMap.subscribe((params: ParamMap)=>
        {
            let name =params.get('name');
            this.selected_name=name;
            console.log(this.selected_name);
        })

        this.subscription.add(this.dataService.getData().subscribe(data => { //<== added this

            this.zone.run(()=>{
                this.imageArray = data;
            })

        }))







  }

  ngOnDestroy() {
        // unsubscribe to ensure no memory leaks
        this.subscription.unsubscribe();
    }




}
2

There are 2 best solutions below

10
AudioBubble On BEST ANSWER

Try to return dataObs$ as Observable in your DatashareService.ts and replace your Subject by a BehaviorSubject.

import { BehaviorSubject } from 'rxjs/Rx';

export class DatashareService {

    private dataObs$ = new BehaviorSubject<any>({});

    getData() {
        return this.dataObs$.asObservable();
    }

    updateData(data) {
        this.dataObs$.next(data);
    }

    constructor() { }
}
0
Mithil Mohan On

Using BehaviourSubject caused the subscribe method in child component fire twice, first with an initial value {} and then with the last updated value. So I changed it to ReplaySubject which doesn't need an initial value.

import { ReplaySubject } from 'rxjs/Rx';

export class DatashareService {

    private dataObs$ = new ReplaySubject<any>(1);

    getData() {
        return this.dataObs$.asObservable();
    }

    updateData(data) {
        this.dataObs$.next(data);
    }

    constructor() { }
}