Search code examples
angularangular-materialangular-signals

RxResource, Signal, MatTable issues - template show no data


I am new to RxResource API with angular 19. The issue is that the material table doesn't display data loading from rxResource (but there is a little trick that I can make to display it. It doesn't make sense at all the way I did). Here is my code: my template:

  <mat-table #table [dataSource]="dataSource" matSort class="mat-elevation-z8" multiTemplateDataRows>

    <ng-container matColumnDef="webTubeLink">
      <mat-header-cell *matHeaderCellDef mat-sort-header>Tube Link</mat-header-cell>
      <mat-cell *matCellDef="let row">{{row.webTubeLink}}</mat-cell>
    </ng-container>

    <ng-container matColumnDef="videoId">
      <mat-header-cell *matHeaderCellDef mat-sort-header>Video Id</mat-header-cell>
      <mat-cell *matCellDef="let row">{{row.videoId}}</mat-cell>
    </ng-container>

    <ng-container matColumnDef="title">
      <mat-header-cell *matHeaderCellDef mat-sort-header>Title</mat-header-cell>
      <mat-cell *matCellDef="let row">{{row.webTubeTitle}}</mat-cell>
    </ng-container>

    <ng-container matColumnDef="actions">
      <mat-header-cell *matHeaderCellDef>
        <span><i class='bi bi-plus-circle' (click)="addNew()"></i> Add</span>
      </mat-header-cell>

      <mat-cell *matCellDef="let row; let i=index;">

        <span class='bi bi-pencil-fill' (click)="startEdit(row)" style="margin-right: 1rem"> Edit</span>
        <span class='bi bi-trash-fill' (click)="deleteItem(row)"> Delete</span>
      </mat-cell>
    </ng-container>


    <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
    <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
  </mat-table>
  <mat-paginator [pageSizeOptions]="[5, 10, 20]" showFirstLastButtons></mat-paginator>
</div>

here is my code component:

  tubeRecordsRS = rxResource<any[], any>({
    loader: () => this.http.get<any[]>('/Tube/Gettubes')
  });
  tubeRecords = computed(() => {
    this.dataSource = new MatTableDataSource(this.tubeRecordsRS.value());
    this.dataSource.paginator = this.paginator;
    return this.tubeRecordsRS.value();
  })

Here is my fix to display data in material table by adding the code below to the template

<p style="display: none">{{ tubeRecords() | json }}</p>

with the code the app is working as it supposed to.

Why? What did I do wrong? Is there any other way to fix this issue?


Solution

  • This can be classified as derived state, we can achieve it in two ways:

    Encapsulate inside the rxResource loader using rxjs operators:

    tubeRecordsRS = rxResource<any[], any>({
      loader: () => this.http.get<any[]>('/Tube/Gettubes').pipe(
        map((response: any) => {
          const dataSource = new MatTableDataSource(response);
          dataSource.paginator = this.paginator;
          return dataSource;
        })
      )
    });
    
    HTML:
    <mat-table #table [dataSource]="tubeRecordsRS.value()" matSort class="mat-elevation-z8" multiTemplateDataRows>
      ...
    

    Use a computed to get the data source:

    tubeRecordsRS = rxResource<any[], any>({
      loader: () => this.http.get<any[]>('/Tube/Gettubes')
    });
    tubeRecords = computed(() => {
      const dataSource = new MatTableDataSource(this.tubeRecordsRS.value());
      dataSource.paginator = this.paginator;
      return dataSource;
    })
    
    HTML:
    <mat-table #table [dataSource]="tubeRecords()" matSort class="mat-elevation-z8" multiTemplateDataRows>
      ...