D052057
D052057

Reputation: 185

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?

Upvotes: 1

Views: 97

Answers (2)

JSON Derulo
JSON Derulo

Reputation: 17758

As you can read in the docs, the computation inside the computed function is only executed if the signal value is actually read, which is not the case in your app, unless the paragraph is added which includes the signal read. Which means that your data source is never constructed.

A better way to connect your data source with the resource's data is via an effect:

export class YourComponent implements AfterViewInit {
  tubeRecordsRS = rxResource<any[], any>({
    loader: () => this.http.get<any[]>('/Tube/Gettubes')
  });
  dataSource = new MatTableDataSource();
  constructor() {
    effect(() => {
      this.dataSource.data = this.tubeRecordsRS.value();
    });
  }
  ngAfterViewInit() {
    this.dataSource.paginator = this.paginator;
  }
}

Upvotes: 1

Naren Murali
Naren Murali

Reputation: 57986

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>
  ...

Upvotes: 1

Related Questions