0

I have an Angular project which has a chart generated by ng2-charts which is populated by data entered by the user themselves via a select box for the labels and an input field for the data. While I can get it to update with the data, if I change the values at all then it won't update the values, it'll just add them as new ones. See the screenshots below:

Add the data the first time

"Updating" the data

I've tried checking on here and other areas of the web, but I haven't found an answer that solves my problem. I believe it has something to do with targeting the specific area of the array, but I can't quite hit upon the right code to do so.

Here is my current code which will allow me to add the data but not update. I'm quite new to Angular so forgive me if some of the code is a bit... rustic.

HTML:


        <div class="deposit-container">
          <div class="chart-container">
            <canvas
              baseChart
              width="290"
              height="290"
              [data]="doughnutChartData"
              [labels]="doughnutChartLabels"
              [options]="doughnutChartOptions"
              [colors]="doughnutChartColors"
              [chartType]="doughnutChartType"
            ></canvas>
          </div>
          <div class="source-container">
            <div
              *ngFor="let depositSource of depositSources; let depositParent = index"
              id="{{ 'source' + depositParent }}"
              class="deposit-source"
            >
              <mat-form-field class="dropdown">
                <mat-select placeholder="Deposit source" [(ngModel)]="depositSourceValue[depositParent]" [ngModelOptions]="{ standalone: true }" (selectionChange)="getLabel(depositParent)">
                  <mat-option
                    *ngFor="let deposit of deposits; let depositSourceOption = index"
                    [value]="deposit.value"
                    id="{{ 'option' + depositSourceOption }}"
                  >
                    {{ deposit.value }}
                  </mat-option>
                </mat-select>
              </mat-form-field>
              <mat-form-field class="textfield">
                <input
                  matInput
                  currencyMask
                  [options]="{ align: 'right', prefix: '£ ', thousands: ',', precision: 0 }"
                  placeholder="£ 0"
                  [(ngModel)]="depositSourceAmount[depositParent]"
                  [ngModelOptions]="{ standalone: true }"
                  (focusout)="getData(depositParent)"
                />
              </mat-form-field>
              <mat-icon (click)="removeDeposit(depositSource); removeData();">delete</mat-icon>
            </div>
            <a id="addDepositSource" (click)="appendDeposit()">+ Add Deposit Source</a>
          </div>
        </div>

TS file:


      deposits: Deposit[] = [
        { value: 'Builders Gift', viewValue: 'Builders Gift' },
        { value: 'Gift', viewValue: 'Gift' },
        { value: 'Loan', viewValue: 'Loan' },
        { value: 'Savings', viewValue: 'Savings' },
        { value: 'Sale of Property', viewValue: 'Sale of Property' },
        { value: 'Inheritance', viewValue: 'Inheritance' },
        { value: 'Vendor Gifted', viewValue: 'Vendor Gifted' },
        { value: 'Equity', viewValue: 'Equity' },
        { value: 'Forces Help to Buy Loan', viewValue: 'Forces Help to Buy Loan' },
        { value: 'Help to Buy ISA', viewValue: 'Help to Buy ISA' },
        { value: 'Porting', viewValue: 'Porting' },
        { value: 'Other', viewValue: 'Other' },
      ];

      public doughnutChartLabels: any [] = [];
      public doughnutChartData: any [] = [];
      public doughnutChartType = 'doughnut';

      public doughnutChartOptions = {
        legend: {
          display: false,
        }
      };

      public doughnutChartColors: Array<any> = [
        {
          backgroundColor: [
            'rgba(0,0,0,0.1)',
            'rgba(254, 11, 48, 1)',
            'rgba(86, 223, 144, 1)',
            'rgba(186, 223, 86, 1)',
            'rgba(191, 86, 223, 1)',
            'rgba(235, 5, 5, 1)',
            'rgba(43, 203, 186, 1)',
            'rgba(5, 235, 235, 1)',
            'rgba(169, 86, 223, 1)',
            'rgba(252, 92, 101, 1)',
            'rgba(86, 160, 223, 1)',
            'rgba(102, 86, 223, 1)',
            'rgba(223, 86, 218, 1)',
          ],
          hoverBackgroundColor: [
            'rgba(0,0,0,0.1)',
            'rgba(254, 11, 48, 1)',
            'rgba(86, 223, 144, 1)',
            'rgba(186, 223, 86, 1)',
            'rgba(191, 86, 223, 1)',
            'rgba(235, 5, 5, 1)',
            'rgba(43, 203, 186, 1)',
            'rgba(5, 235, 235, 1)',
            'rgba(169, 86, 223, 1)',
            'rgba(252, 92, 101, 1)',
            'rgba(86, 160, 223, 1)',
            'rgba(102, 86, 223, 1)',
            'rgba(223, 86, 218, 1)',
          ],
          borderWidth: 0
        },
      ];

      getLabel(depositParent) {
        let target = this.depositSourceValue[depositParent];
        this.doughnutChartLabels.push(target);
        this.chart.chart.update();
      }

      getData(depositParent) {
        let data = this.depositSourceAmount[depositParent];
        this.doughnutChartData.push(data);
        this.chart.chart.update();
      }

I've tried adding on the index value on like so:

    this.doughnutChartLabels[depositParent].push(target);

    this.doughnutChartData[depositParent].push(data);

But this just gives me the following error:

DigitalPortalComponent.html:30 ERROR TypeError: this.doughnutChartLabels[depositParent].push is not a function
    at DigitalPortalComponent.getLabel (digital-portal.component.ts:499)

I've also tried setting up the chart with a dataset:

HTML:

    <canvas
      baseChart
      width="290"
      height="290"
     [datasets]="doughnutChartDataset"
     [labels]="doughnutChartLabels"
     [options]="doughnutChartOptions"
     [colors]="doughnutChartColors"
     [chartType]="doughnutChartType"></canvas>

TS:


      public doughnutChartDataset: any [] =
      [
        { data: [], label: 'Deposit Source' }
      ];

      public doughnutChartLabels: any [] = ['a'];
      public doughnutChartType = 'doughnut';

      public doughnutChartOptions = {
        legend: {
          display: false,
        }
      };

But I can't figure out how to push the data to a dataset so I can't even get as far as adding data to the chart with this method.

Anyone have any ideas? I feel like I'm not far off, but can't quite crack it.

EDIT:

Tried using "splice" to see if I could update the relevant data in the array, but this doesn't work either. Just serves to add the data onto the end of the array still.

  changeData(depositParent) {
    let depositData = this.depositSourceAmount[depositParent];
    this.doughnutChartData.splice(depositParent, 0, depositData);
    this.chart.chart.update();
  }

Getting to the end of my rope. Has anyone had to do anything similar here where they need to dynamically edit data within an array?

RocketMatt
  • 107
  • 4
  • 13
  • What is `depositSourceValue`? – ahmeticat Jul 19 '19 at 08:45
  • Hi @ahmeticat - ```depositSourceValue``` is taken from the ngModel in select: ``` {{ deposit.value }} ``` – RocketMatt Jul 19 '19 at 08:57
  • You are accessing an element of the array and you try to push some data there? Have you tried `this.doughnutChartLabels.push(target)` ? – Orestis Zekai Jul 19 '19 at 09:26
  • @OrestisZekai - I'm not quite sure what you're asking me to change there, as I already have that in my code...? – RocketMatt Jul 19 '19 at 09:34
  • In your code you have this `this.doughnutChartLabels[depositParent].push(target);`. Try getting rid of accessing the element and just push in the array, like my previous comment – Orestis Zekai Jul 19 '19 at 10:02
  • @OrestisZekai - Ah, I see. Yes, I've tried that and it still gives me the same result. I haven't been able to successfully update the array. It always adds it on as new data, rather than updating the array. – RocketMatt Jul 19 '19 at 10:05
  • Have you tried a change detector? https://angular.io/api/core/ChangeDetectorRef#detectchanges – Orestis Zekai Jul 19 '19 at 10:16
  • @OrestisZekai - I haven't no, but I'm not sure how I would use it in this instance, since I still can't figure out how to change the part of the chart arrays that I need to. As I said, I'm fairly new to Angular and I'm at the point where beating my head against a brick wall would be more productive for me, hence asking for help on here. :( – RocketMatt Jul 19 '19 at 10:47

1 Answers1

0

I also encountered this problem when trying to apply translations to the labels I used in the graph. I have read somewhere also here in stackoverlfow that you have to change the reference of the array you are using in the graph.

For your example, you can try

 getLabel(depositParent) {
    let target = this.depositSourceValue[depositParent];
    this.doughnutChartLabels = [...this.doughnutChartLabels, depositParent];
    // this.chart.chart.update();
  }

  getData(depositParent) {
    let data = this.depositSourceAmount[depositParent];
    this.doughnutChartData = [...this.doughnutChartData, depositParent];
    // this.chart.chart.update();
  }

I would also suggest that you use a service that holds an Observable and let this component subscribe to it so that it receives the notification and call the code that updates the graph.

Hope this helps.

carloliwanag
  • 348
  • 3
  • 12