Search code examples
angularplotly

How to share data between components and provide it for a plotly chart


Let me explain first what the working part is in my project:

dataframe.component: A button is emitting an event which calls a function Initdf() which initiates a service which retrieves JSON data from my backend API. I map two values from this data and assign them to arrays. dfClose and dfDateTime.

With these two arrays I want to feed a plotly.js chart in plotly1.component

I'm trying to achieve the data sharing between the components with @Input() and @Output() properties.

What is not working:

In my plotly1.component, I imported the onChanges method to listen to updates on the data (when button is clicked), but I get tons of repeated error messages:

core.mjs:6485 ERROR TypeError: Cannot read properties of undefined (reading 'data')

I cannot complete the onChanges method because the angular doc is not detailed enough for me. I can't help myself with it alone.

dataframe.component.ts:

import { Component, OnInit, Output } from '@angular/core';
import { RestServiceDfinit } from '../../services/rest-df-init.service';
import { DfIndicatorService } from '../../services/rest-df-indicator.service';
import {Plotly1Component} from '../plotly1/plotly1.component';

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

  df_array: any = [];
  tabVal:any = [];
  tabKey:any = [];
  df_standard_tab_order: any;
  toggleAdd: boolean = true;
  toggleDelete: boolean = true;

  @Output() dfClose:any;
  @Output() dfDateTime:any;


  constructor(private restService: RestServiceDfinit, private indicatorService: DfIndicatorService) {}//, private plotly: Plotly1Component) {}

  ngOnInit(): void {  }

  Initdf() {
    this.restService.postTickerGetDf().subscribe((response) => {
      this.df_array = response;
      this.dfClose = this.df_array.map((x: any) => x.Close);
      this.dfDateTime = this.df_array.map((x: any) => x.DateTime);
      
      .....

plotly1.component.ts:

import { Component, OnInit, Input, OnChanges } from '@angular/core';
import {Plotly1Service} from '../../services/plotly1.service'
import {Observable} from 'rxjs'

@Component({
  selector: 'app-plotly1',
  template: '<plotly-plot [data]="graph.data" [layout]="graph.layout"></plotly-plot>'
})


export class Plotly1Component implements OnChanges {


  public graph:any;

  @Input() dfClose:any;
  @Input() dfDateTime:any;

  constructor(private plotlyService: Plotly1Service) { }

  ngOnChanges(changes: SimpleChanges): void {
    this.fill_data();
    }
   
  fill_data() {
    this.graph = {
      data: [
          { x: this.dfDateTime, y:  this.dfClose, type: 'scatter', mode: 'lines', marker: {color: 'blue'} },
        
      ],
      layout: {width: 1320, height: 600, title: 'test Plot'}}}}

Is it the right path to go with onChanges? How to I complete it?

Update: I skipped the plotly.component for testing and tried to get the data from setData in dataframe.component.ts in a div :

  Initdf() {
    this.restService.postTickerGetDf().subscribe((response) => {
      this.df_array = response;
      const close = response.map(x => x.Close);
      const dateTime = response.map(x => x.DateTime);
      this.mappedData.emit({
         dfClose: close,
         dfDateTime: dateTime
      });
      this.setData(this.mappedData);
    
  setData(mappedData:any) {

    this.dfClose = mappedData.dfClose;
    this.dfDateTime = mappedData.dfDateTime;

    this.graph = {
    data: [
        { x: this.dfDateTime, y:  this.dfClose, type: 'scatter', mode: 'lines', marker: {color: 'blue'} },
      
    ],
    layout: {width: 1320, height: 600, title: 'test Plot'}}

in dataframe.component.html I tried these variations:

  <div (mappedData)="setData($event)">{{graph}}</div>
  <div (mappedData)="setData($event)">{{mappedData}}</div>
  <div >{{graph}}</div>
  <div >{{mappedData}}</div>

It also doesn't work. In the best case I see [object Object]


Solution

  • I found the solution by myself. It works well with my initial idea to use the OnChanges lifecycle hook.

    dataframe component ts:

      Initdf() {
        this.restService.postTickerGetDf().subscribe((response) => {
          this.df_array = response;
    

    dataframe html:

    <app-plotly1 [df_array]="df_array"></app-plotly1>  
    

    plotly1 component ts:

    @Input() df_array:any;
    
      ngOnChanges(changes: SimpleChanges): void {
        this.dfClose = this.df_array.map((x: any) => x.Close);
        this.dfDateTime = this.df_array.map((x: any) => x.DateTime);