如何在组件之间共享数据并将其提供给绘图图

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

让我先解释一下我项目中的工作部分是什么:

dataframe.component:按钮正在发出调用函数 Initdf() 的事件,该函数会启动从我的后端 API 检索 JSON 数据的服务。我从该数据映射两个值并将它们分配给数组。 dfClosedfDateTime.

有了这两个数组,我想在 plotly1.component

中提供 plotly.js 图表

我正在尝试实现具有 @Input()@Output() 属性的组件之间的数据共享。

什么不起作用:

在我的 plotly1.component 中,我导入了 onChanges 方法来监听数据的更新(当按钮被点击时),但是我收到大量重复的错误信息:

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

我无法完成 onChanges 方法,因为 angular 文档对我来说不够详细。我一个人无法自拔。

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'}}}}

使用 onChanges 是否正确?如何完成?

更新:我跳过了 plotly.component 进行测试,并尝试从 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'}}

在 dataframe.component.html 我尝试了这些变体:

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

同样不行。在最好的情况下,我看到 [object Object]

我认为您不了解@Input() 和@Output() 工作流程。 @Output() 它是一个 EventEmitter,它必须发出一个值才能在 parent 组件上接收它。你甚至不需要两个输出。您应该使用一个根据您的需要发出 object 的输出。

// in your child
@Output mappedData = new EventEmitter();

然后在你的函数中你正在做类似的事情:

// in your child Initdf() function
const close = response.map(x => x.Close);
const dateTime = response.map(x => x.DateTime);
this.mappedData.emit({
   dfClose: close,
   dfDateTime: dateTime
});

然后您将在 parent 组件中捕获这些事件。

// in your parent html file
<app-dataframe (mappedData)="setData($event)></app-dataframe    

然后在您的 parent 组件中,您可以使用数据完成您的工作。

// in your parent ts file
setData(mappedData) {
  // here you have access to mappedData.dfClose and mappedData.dfDateTime
}

其次,你应该开始使用类型而不是那么多'any'。防止错误要容易得多。 这就是您所需要的。您可以删除这些@Input。您不需要它们,因为您是通过 child.

的 @Output 获取数据的

我自己找到了解决方案。它很符合我最初的想法,即使用 OnChanges 生命周期钩子。

数据框组件 ts:

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

数据帧html:

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

plotly1 组件 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);