问题
I am trying to create a common ng2-charts (Bar Stacked) component, where I can pass the data from other component and it will get update. Actually, I want to display multiple same stacked bar charts with different values in the same page while loading the page.
I have created one common component with ng-2 charts and created one service also. Now I am calling the common component from one more different component via shared service with different parameter, but it is always showing first component value.
my first component (bar-chart.component.ts),
import { Component, OnInit } from "@angular/core";
import { ChartOptions, ChartType, ChartDataSets } from "chart.js";
import * as pluginDataLabels from "chartjs-plugin-datalabels";
import { Label } from "ng2-charts";
import { BarChartService } from "../service/bar-chart.service";
@Component({
selector: "app-bar-chart",
templateUrl: "./bar-chart.component.html",
styleUrls: ["./bar-chart.component.css"]
})
export class BarChartComponent implements OnInit {
public barChartOptions: ChartOptions = {
responsive: true,
// We use these empty structures as placeholders for dynamic theming.
scales: {
xAxes: [
{
stacked: true
}
],
yAxes: [
{
stacked: true
}
]
},
plugins: {
datalabels: {
anchor: "end",
align: "end"
}
}
};
public barChartLabels: Label[] = [
"2006",
"2007",
"2008",
"2009",
"2010",
"2011",
"2012"
];
public barChartType: ChartType = "bar";
public barChartLegend = true;
public barChartPlugins = [pluginDataLabels];
public barChartData: ChartDataSets[] = [];
constructor(private barchartservice: BarChartService) {}
ngOnInit() {
this.barChartData = this.barchartservice.getBarChartData("one");
}
// events
public chartClicked({
event,
active
}: {
event: MouseEvent;
active: {}[];
}): void {
console.log(event, active);
}
public chartHovered({
event,
active
}: {
event: MouseEvent;
active: {}[];
}): void {
console.log(event, active);
}
public randomize(): void {
// Only Change 3 values
const data = [
Math.round(Math.random() * 100),
59,
80,
Math.random() * 100,
56,
Math.random() * 100,
40
];
this.barChartData[0].data = data;
}
}
in the first bar-chart.component.html,
<div style="display: block">
<canvas
baseChart
[datasets]="barChartData"
[labels]="barChartLabels"
[options]="barChartOptions"
[plugins]="barChartPlugins"
[legend]="barChartLegend"
[chartType]="barChartType"
>
</canvas>
</div>
In the second-bar-chart.component.ts,
import { Component, OnInit } from "@angular/core";
import { ChartOptions, ChartType, ChartDataSets } from "chart.js";
import * as pluginDataLabels from "chartjs-plugin-datalabels";
import { Label } from "ng2-charts";
import { BarChartService } from "../service/bar-chart.service";
@Component({
selector: "app-second-bar-chart",
templateUrl: "./second-bar-chart.component.html",
styleUrls: ["./second-bar-chart.component.css"]
})
export class SecondBarChartComponent implements OnInit {
public barChartData: ChartDataSets[] = [];
constructor(private barchartservice: BarChartService) {}
ngOnInit() {
this.barChartData = this.barchartservice.getBarChartData("two");
}
}
in the, second-bar-chart.component.html,
<h3>This is 2nd Bar Chart</h3>
<app-bar-chart></app-bar-chart>
in the service (bar-chart.service.ts), I am writing like this,
import { Injectable } from "@angular/core";
@Injectable({
providedIn: "root"
})
export class BarChartService {
constructor() {}
getBarChartData(chartType) {
if (chartType == "one") {
return [
{ data: [65, 59, 80, 81, 56, 55, 40], label: "Series A", stack: "1" },
{ data: [28, 48, 40, 19, 86, 27, 90], label: "Series B", stack: "1" }
];
} else {
return [
{ data: [40, 59], label: "Male", stack: "1" },
{ data: [90, 48], label: "Female", stack: "1" }
];
}
}
}
I am expecting two different charts values but in both the component, it is showing only the first component chart value.
Please help me.
回答1:
The problem with your code is the common component is not getting data from the parent component(2nd component) but it is getting its own data from the service using
ngOnInit() {
this.barChartData = this.barchartservice.getBarChartData("one");
}
One way would be to get barChartData
outside of the component as Input
property. In this way every parent component will give the necessary data to your common component and the job of your common component will be to just display it.
You can use Input to get data from outside of component.
You code will be like this:
bar-chart.component.ts
import { Component, OnInit, Input } from "@angular/core";
import { ChartOptions, ChartType, ChartDataSets } from "chart.js";
import * as pluginDataLabels from "chartjs-plugin-datalabels";
import { Label } from "ng2-charts";
import { BarChartService } from "../service/bar-chart.service";
@Component({
selector: "app-bar-chart",
templateUrl: "./bar-chart.component.html",
styleUrls: ["./bar-chart.component.css"]
})
export class BarChartComponent implements OnInit {
@Input() barChartData: ChartDataSets[]; // <- note this line
public barChartOptions: ChartOptions = {
responsive: true,
// We use these empty structures as placeholders for dynamic theming.
scales: {
xAxes: [
{
stacked: true
}
],
yAxes: [
{
stacked: true
}
]
},
plugins: {
datalabels: {
anchor: "end",
align: "end"
}
}
};
public barChartLabels: Label[] = [
"2006",
"2007",
"2008",
"2009",
"2010",
"2011",
"2012"
];
public barChartType: ChartType = "bar";
public barChartLegend = true;
public barChartPlugins = [pluginDataLabels];
constructor(private barchartservice: BarChartService) {}
ngOnInit() {}
// events
public chartClicked({
event,
active
}: {
event: MouseEvent;
active: {}[];
}): void {
console.log(event, active);
}
public chartHovered({
event,
active
}: {
event: MouseEvent;
active: {}[];
}): void {
console.log(event, active);
}
public randomize(): void {
// Only Change 3 values
const data = [
Math.round(Math.random() * 100),
59,
80,
Math.random() * 100,
56,
Math.random() * 100,
40
];
this.barChartData[0].data = data;
}
}
Now in your parent component you can get the parentChartData
through your Service
and then give it to your common component like this:
parent.component.html
<app-first-bar-chart [barChartData]="parentChartData"></app-first-bar-chart>
In this way, you can use this component anywhere in your app and just provide it with the data(barChartData) and it will display it
Update
In order to make your BarChartComponent
fully reusable. You can get the other attributes(labels
, chartType
etc) of your chart from the parent component.
You code will include other Input
properties
import { Component, OnInit, Input } from "@angular/core";
import { ChartOptions, ChartType, ChartDataSets } from "chart.js";
import * as pluginDataLabels from "chartjs-plugin-datalabels";
import { Label } from "ng2-charts";
import { BarChartService } from "../service/bar-chart.service";
@Component({
selector: "app-bar-chart",
templateUrl: "./bar-chart.component.html",
styleUrls: ["./bar-chart.component.css"]
})
export class BarChartComponent implements OnInit {
@Input() barChartData: ChartDataSets[]; // <- note this line
@Input() labels: Label[];
@Input() chartType: ChartType;
And your component tag would be like this:
<app-first-bar-chart [chartType]="'bar'" [labels]="myLabelsArray" [barChartData]="parentChartData"></app-first-bar-chart>
来源:https://stackoverflow.com/questions/56306678/how-to-create-one-common-angular-ng2-charts-bar-chart-component-which-can-be-c