Search code examples
angulartypescriptangular8ng2-charts

Ng2-Chart - Assign JSON Data To DataSet


I have the below JSON data and these are attendance details for the few last days:

[
    {
        "date": "2021-09-07T00:00:00",
        "type": "Teacher",
        "total": 744
    },
    {
        "date": "2021-09-07T00:00:00",
        "type": "Student",
        "total": 4769
    },
    {
        "date": "2021-09-08T00:00:00",
        "type": "Teacher",
        "total": 740
    },
    {
        "date": "2021-09-08T00:00:00",
        "type": "Student",
        "total": 4743
    },
    {
        "date": "2021-09-09T00:00:00",
        "type": "Teacher",
        "total": 736
    },
    {
        "date": "2021-09-09T00:00:00",
        "type": "Student",
        "total": 4714
    },
    {
        "date": "2021-09-10T00:00:00",
        "type": "Teacher",
        "total": 52
    },
    {
        "date": "2021-09-10T00:00:00",
        "type": "Student",
        "total": 47
    },
    {
        "date": "2021-09-11T00:00:00",
        "type": "Teacher",
        "total": 648
    },
    {
        "date": "2021-09-11T00:00:00",
        "type": "Student",
        "total": 4341
    }
]

I am using a template for test purposes and this is the link for it, it uses ng2-chart:

Purple Angular

GitHub Link: GitHub Link

I tried to assign those JSON data into a dataset and tried to use the ng2-chart from the template:

Chart

My plan is to show the last 4/6 days' attendance data (JSON data) in the chart as dates in the horizontal line and in the vertical line, it'll have the teacher/student total attendance for specific dates. I analyzed the chart already and tried something as follows:

//Get Last Four Days Data
LoadLastFour() {
  debugger;
  this.dataservice.GetLastFour().subscribe(result => {
    this.lastFour = JSON.parse(result);

    this.visitSaleChartData = [{
      label: this.lastFour.map((m: any) => m.type),
      data: this.lastFour.map((m: any) => m.total),
      borderWidth: 1,
      fill: false,
    }];

    this.visitSaleChartLabels = [this.lastFour.map((m: any) => m.date)]

    console.log(this.lastFour);
  }, error => console.error(error)); 
} 

In the template, it has data source as follows:

<canvas baseChart #visitSaleChart 
    [chartType]="'bar'" *ngIf="visitSaleChartData" 
    [datasets]="visitSaleChartData" [labels]="visitSaleChartLabels" 
    [options]="visitSaleChartOptions" [colors]="visitSaleChartColors"></canvas>
visitSaleChartData = [{
  label: 'CHN',
  data: [20, 40, 15, 35, 25, 50, 30, 20],
  borderWidth: 1,
  fill: false,
},
{
  label: 'USA',
  data: [40, 30, 20, 10, 50, 15, 35, 40],
  borderWidth: 1,
  fill: false,
},
{
  label: 'UK',
  data: [70, 10, 30, 40, 25, 50, 15, 30],
  borderWidth: 1,
  fill: false,
}];

visitSaleChartLabels = ["2013", "2014", "2014", "2015", "2016", "2017"];

The issue is when I render the chart in the front-end, it shows only a bar and under it, all the dates are aligned row by row though it should create the dates horizontally side by side.

Any way that I can make it work or require anything specific?

Working Sample: Stackblitz


Solution

  • Concept

    1. Group lastFour data by type (Student/Teacher).
    2. Remove key from groupedByTypeResult (Step 1) to append to chartData and for visitSaleChartData.
    3. Format date with DatePipe and Distinct date (remove duplicates) for visitSaleChartLabels.

    Solution

    app.component.html

    <div style="display: block;">
      <canvas baseChart #visitSaleChart 
        [chartType]="'bar'" 
        *ngIf="visitSaleChartData" 
        [datasets]="visitSaleChartData" 
        [labels]="visitSaleChartLabels" 
        [options]="visitSaleChartOptions" 
        [colors]="visitSaleChartColors" 
        ></canvas>
    </div>
    
    export class AppComponent {
    
      lastFour: any[] = [];
      visitSaleChartData: ChartDataSets[] = [];
      visitSaleChartLabels = [];
      visitSaleChartOptions = {};
      visitSaleChartColors = [];
    
      constructor(private dataservice: DataService, private datePipe: DatePipe) {}
    
      ngOnInit() {
        this.LoadLastFour();
      }
    
      LoadLastFour() {
        this.dataservice.GetLastFour().subscribe(
          result => {
            this.lastFour = result;
    
            // Group Last Four by Type
            let groupedByTypeResult: any[] = this.lastFour.reduce(function(
              obj: any,
              item: any
            ) {
              let type = item.type;
    
              obj[type] = obj[type] || { label: item.type, data: [] };
              obj[type].data.push(item.total);
    
              return obj;
            },
            {});
    
            // Remove key to append to chartData
            let chartData = [];
            for (let type in groupedByTypeResult) {
              chartData.push({
                label: groupedByTypeResult[type].label,
                data: groupedByTypeResult[type].data,
                borderWidth: 1,
                fill: false
              });
            }
    
            this.visitSaleChartData = chartData;
    
            // Distinct date for chartLabel
            this.visitSaleChartLabels = [
              ...new Map(
                this.lastFour.map(item => [
                  item.date,
                  this.datePipe.transform(item.date, 'yyyy-MM-dd')
                ])
              ).values()
            ];
          },
          error => console.error(error)
        );
      }
    }
    

    Sample Solution on StackBlitz

    Output

    enter image description here