Youssef ElZawawy
Youssef ElZawawy

Reputation: 139

Child component does not update when signal changes in angular 17

In my Statistics module I got a signal that defines the type of the charts that should appear and this signal is updated using a radio button group. The signal: typeSignal = signal<string>('OIA')

The radio buttons that sets the :

<div class="btn-group w-auto" role="group">
     @for (type of types; track $index) {
            <input type="radio" class="btn-check" name="btnradio" [id]="type" autocomplete="off"
                [checked]="type==typeSignal()">
            <label class="btn btn-primary" for="btnradio1" (click)="typeSignal.set(type)">{{type}}</label>
     }
</div>

However, I got another computed signal that creates the charts data according to the type signal. Here's the charts signal:

  charts = computed(() => {
    const chartsArr:ChartData[] = []
   if (this.typeSignal() == "OIA") {

      chartsArr.push(this.createBarChart("Status of Incident", ['Closed', 'Ongoing'], "status", "Advisories", true))
      chartsArr.push(this.createBarChart("Severity of Incident", ['Severity 0', 'Severity 1', 'Severity 2', 'Severity 3', 'Severity 4'], "impacts", "Advisories", false))
      chartsArr.push(this.createDonutChart("Communication type", ['Incident', 'Change'], 300))

    } else if (this.typeSignal() == "Portail de l'information") {

      chartsArr.push(this.createBarChart("Status of Incident", ['Scheduled', 'Archived', 'Ongoing'], "status", "Advisories", true))
      chartsArr.push(this.createBarChart("Impact of Incident", ['Major', 'Minor', 'Grave'], "impacts", "Advisories", false))
      chartsArr.push(this.createDonutChart("Communication type", ['Incident', 'Change'], 300))

    } else if (this.typeSignal() == "Bulletin Board") {
      chartsArr.push(this.createBarChart("Status of Change", ['Closed', 'Ongoing', 'Scheduled'], "status", "Advisories", true))
      chartsArr.push(this.createBarChart("Outage of Incident", ['Complete Outage', 'Partial Outage', 'Info'], "impacts", "Advisories", false))
      chartsArr.push(this.createDonutChart("Communication type", ['Info', 'Incident', 'Change'], 300))
    }
    console.log(chartsArr);
    return structuredClone(chartsArr)
  })

and I read this charts signal in my template

@if (["OIA","Portail de l'information","Bulletin Board"].includes(typeSignal())) {
<div class="row row-cols-2 g-5 mx-1">
    @for (chart of charts(); track $index) {
    @if (chart.type == "bar") {
    <app-bar-chart [title]="chart.title" [axissLabels]="chart.labels" [values]="chart.values"
        [valuesType]="chart.valuesType!" [isHorizontal]="chart.isHorizontal!"></app-bar-chart>
    }@else if (chart.type=="donut") {
    <app-donut-chart [title]="chart.title" [values]="chart.values" [labels]="chart.labels"
        [minWidth]="chart.minWidth!"></app-donut-chart>
    }
    }

</div>
}

The problem here is that the charts signal doesn't update the for loop although the console.log(chartsArr); inside it gets logged whenever I toggle the radio buttons.

Upvotes: 2

Views: 701

Answers (1)

Youssef ElZawawy
Youssef ElZawawy

Reputation: 139

I found that the problem wasn't in the signal itself.

The problem was related with the child components BarChartComponent and DonutChartComponent.

They weren't detecting the update changes. So, I added OnChanges.

Here's the code of DonutChartComponent after modification:

export type ChartOptions = {
  series: ApexNonAxisChartSeries;
  chart: ApexChart;
  responsive: ApexResponsive[];
  labels: string[];
  title: ApexTitleSubtitle;
};

@Component({
  selector: 'app-donut-chart',
  standalone: true,
  imports: [NgApexchartsModule],
  templateUrl: './donut-chart.component.html',
  styleUrl: './donut-chart.component.scss'
})
export class DonutChartComponent implements OnInit, OnChanges {
  @ViewChild("chart") chart!: ChartComponent;
  chartOptions!: Partial<ChartOptions>;

  @Input() values: number[] = []
  @Input() labels: string[] = []

  @Input() title!: string
  @Input() minWidth!: number


  ngOnInit(): void {
    this.createChart()
  }
  ngOnChanges(changes: SimpleChanges) {
    if (Object.keys(changes).length > 0) {
      if (changes['values']?.currentValue) {
        this.values = changes['values']?.currentValue
      }
      if (changes['labels']?.currentValue) {
        this.labels = changes['labels']?.currentValue
      }
      if (changes['title']?.currentValue) {
        this.title = changes['title']?.currentValue
      }
      if (changes['minWidth']?.currentValue) {
        this.minWidth = changes['minWidth']?.currentValue
      }
      this.createChart()
    }
  }

  createChart() {
    this.chartOptions = {
      title: {
        text: this.title
      },
      series: this.values,
      chart: {
        type: "donut",
      },
      labels: this.labels,
      responsive: [
        {
          breakpoint: this.minWidth,
          options: {
            chart: {
              width: this.minWidth,
            },
            legend: {
              position: "bottom",
            },
          },
        },
      ],
    };
  }

}

Upvotes: 0

Related Questions