0

I have been struggling with passing an array from one component to another. The issue is that when the array is pass between components it is empty. I can see in the console that the array is filled with integers, but it is being pass before any values are push into it. I have tried multiple things and after an extensive research found that the best approach would be to use BehaviorSubject as describe in this thread: Angular 4 pass data between 2 not related components

The only thing is that in the example provided they are passing a string. I have been trying to find another good example like the one mentioned above but instead of passing strings it would need to be an integer array. service.ts is the shared service between compA and compB. compA is the component that needs to receive the array from compB. compB is the component that has the array needed to be pass to compA. With that being said, which component would need to subscribe to the BehaviorSubject? A simplified version of my code is given below with the commented lines being what I have come up with so far to implement BehaviorSubject with an array.

Shared Service - service.ts

    import { Injectable } from '@angular/core';
    import { HttpClient, HttpParams } from '@angular/http';
    import { BehaviorSubject } from 'rxjs/BehaviorSubject';
    import { RootService } from '../../../common/root-service/root.service';


   @Injectable()
    export class service {
    
    //dataSource: BehaviorSubject<Array<number>> = new BehaviorSubject([]);
    //dataPlot = this.userDataSource.asObservable();


    dataPlot: Array<number> = [];

    

    constructor(private http: HttpClient, private appRootService: RootService) { }
    
    ... Some Code ...
    
    /**
    updateDataPlot(data) {
        this.dataSource.next(data);
    }
    */

    setDataPlot(data: Array<number>) {
        this.dataPlot = data; 
    }

    getDataPlot(): Array<number> {
         return this.dataPlot;
    }
}

ComponentA - compA.ts

import { Component, HostListener } from '@angular/core';
import { service } from '../../..common/service';
 
... Some Code...

@Component({
    selector: 'compA',
    styleUrls: ['./compA.css'],
    templateUrl: './compA.html'
})

export class compA {

... Some Code ...

dataPlotArray: Array<number>;

constructor(private sw: Service){
     this.getDataPlot();
}

... Some Code ...


getDataPlot() {
     this.dataPlotArray = this.sw.getDataPlot()
}

... Rest of Code ...

ComponentB - compB.ts

import { Component, HostListener } from '@angular/core';
import { service } from '../../..common/service';
 
... Some Code...

@Component({
    selector: 'compB',
    styleUrls: ['./compB.css'],
    templateUrl: './compB.html'
})

export class compB {

... Some Code ...

dataPlot: Array<number> = [];

constructor(private sw: Service){
     this.setDataPlot();
}

... Some Code ...

/**
setDataPlot() {
   this.sw.setDataPlot.subscribe((this.dataPlot) => { 
     this.sw.updateDataPlot(this.dataPlot);
  })
}
*/

setDataPlot() {
     this.sw.setDataPlot(this.dataPlot);
}

... Rest of Code ...
Alan
  • 19
  • 10

1 Answers1

1

There're a couple of mistakes and extra code that we can get rid of.

At first it's a great practice to start class names with a capital letter. Secondly, you don't need to have methods like getDataPlot(). Use an Observable instead.

Your service:

...
@Injectable()
export class Service {
    
    dataSource$$: BehaviorSubject<Array<number>> = new BehaviorSubject([]);
    dataPlot$ = this.dataSource$$.asObservable();

    constructor(private http: HttpClient, private appRootService: RootService) { }
    
    ... Some Code ...
    
   
    updateDataPlot(data) {
        this.dataSource$$.next(data);
    }

}

Component A:

...

@Component({
    selector: 'compA',
    styleUrls: ['./compA.css'],
    templateUrl: './compA.html'
})

export class CompA {

  ... Some Code ...

  dataPlotArray: Array<number>;

  constructor(private sw: Service){
    this.sw.dataPlot$.subscribe( data=> this.dataPlotArray = data);
  }

... Rest of Code ...
}

Component B:

...

@Component({
    selector: 'compB',
    styleUrls: ['./compB.css'],
    templateUrl: './compB.html'
})

export class CompB {

... Some Code ...

  dataPlot: Array<number> = [];

  constructor(private sw: Service){
    //get data here and assign it to dataPlot variable

    this.setDataPlot();
  }

  ... Some Code ...

  setDataPlot() {
     this.sw.updateDataPlot(this.dataPlot);
  }

}

Dmitry S.
  • 1,544
  • 2
  • 13
  • 22
  • Thank you for your help! The only change I had to do was change setDataPlot() to call to updateDataPlot() inside Component B. Also, I'm new to Angular would you mind explaining to me why you are using dollar signs for the dataSource$$ and dataPlot$ variables? – Alan Jun 01 '21 at 17:28
  • @Alan, it's a great practice to use one dollar sign for the `Observable` and double dollar sign for the `Subject` and its derivatives. – Dmitry S. Jun 01 '21 at 20:20
  • @DmitryS. Doesn't this line `this.sw.setDataPlot(this.dataPlot)` in Component B throw compile error? or that's an `this.sw.updateDataPlot(this.dataPlot);` ?? – A Coder Oct 06 '21 at 10:09
  • @ACoder, you're right it's going to be a `this.sw.updateDataPlot(this.dataPlot);`. Corrected. – Dmitry S. Oct 09 '21 at 10:34