Updating of an Angular computed signal occurs only once but not for future dependencies update

Discussão em 'Angular' iniciado por berno, Janeiro 14, 2025.

  1. berno

    berno Guest

    I'm trying to filter an array based on the value of a signal , I think computed signal is the best option for this purpose. My goal is to show only the results that match (via a custom filtering function) the corresponding feedback filter set in another component via a toggle button.

    Parent component ts file

    export interface Data {
    name: string;
    total_fb: number;
    last30: number;
    trend: string;
    }

    ...

    dataArray = [
    {name: 'Prod XY', total_fb: 4.5, last30: 3.6, trend: 'up'},
    {name: 'Prod lorem ipsum Z', total_fb: 4.2, last30: 3.3, trend: 'up'},
    {name: 'Prod VBG', total_fb: 3.3, last30: 3.7, trend: 'up'},
    {name: 'Prod XYZ', total_fb: 3.7, last30: 2.9, trend: 'down'},
    ...
    ];

    filtersProd = signal({source: '1', feedback: 'all'});

    filteredProdData = computed(() => {
    const rating = this.filtersProd().feedback;
    return this.dataArray.filter((el) => this.filterByFeedBackRating(el, rating));
    });

    filterByFeedBackRating = (data: Data, rating_value: string) => {
    if (rating_value === 'all') {
    return true;
    } else if (rating_value === '4+' && data.total_fb >= 4) {
    return true;
    } else if (rating_value === '3' && data.total_fb >= 3 && data.total_fb < 4) {
    return true;
    } else if (rating_value === '1/2' && data.total_fb < 3) {
    return true;
    }
    return false;
    }



    Parent component template

    <div class="pre-content">
    <pre>source: {{filtersProd().source}} rating: {{filtersProd().feedback}}</pre>
    <app-filter-source-feedback [(filters)]="filtersProd"></app-filter-source-feedback>
    </div>
    <div class="content flex">
    <app-table-performance [data]="filteredProdData()"></app-table-performance>
    </div>


    FilterSourceFeedback component ts file

    filters = model.required<{feedback: string|number, source: string}>();


    FilterSourceFeedback component template

    <div class="toggle">
    <label>Feedback</label>
    <mat-button-toggle-group [(value)]="filters().feedback" hideSingleSelectionIndicator="true" name="feedback" aria-label="feedback rating">
    <mat-button-toggle value="all">all</mat-button-toggle>
    <mat-button-toggle value="4+">4+</mat-button-toggle>
    <mat-button-toggle value="3">3</mat-button-toggle>
    <mat-button-toggle value="1/2">1/2</mat-button-toggle>
    </mat-button-toggle-group>
    </div>


    TablePerformance component ts file

    data = input<Data[]>([]);
    dataSource = computed(() => new MatTableDataSource(this.data()));
    columnsToDisplay = ['name', 'total_fb', 'last30', 'trend'];


    TablePerformance component template

    <table mat-table [dataSource]="dataSource()">
    <ng-container matColumnDef="name">
    <th mat-header-cell *matHeaderCellDef> Name </th>
    <td mat-cell *matCellDef="let tourStat"> {{tourStat.name}} </td>
    </ng-container>
    <ng-container matColumnDef="total_fb">
    <th mat-header-cell *matHeaderCellDef> Total </th>
    <td mat-cell *matCellDef="let tourStat"> {{tourStat.total_fb}} </td>
    </ng-container>

    ...

    <tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr>
    <tr mat-row *matRowDef="let row; columns: columnsToDisplay"></tr>
    </table>


    When I change the value of the feedback toggle button group the filtersProd signal in the parent component is in perfect sync with the model signal filters in the child component. The problem is that the array returned by the computed signal filteredProdData is filtered only with the initial value (if I change the initial value I obtain the correct filtered results in the table), subsequent updates do not filter the initial array as if the computed signal don't 'listen' the updates of its dependencies.

    Since last time I worked with Angular was a version where the signals feature was not released yet I don't understand where I'm going wrong or what I'm missing.

    Continue reading...

Compartilhe esta Página