Search code examples
angularangular-materialangular-material-table

Why isn't my mat-table UI updating when I update the data that it's displaying?


I have a table that is using the data from the array keyData I want to press a button and add a row to that data.

From console.logs I can tell that the keyData array is having the extra row inserted but this is not reflected in the UI.

Here's the HTML:

<mat-tab label="Keys">
  <button mat-fab extended (click)="onAddKey()">
    <mat-icon>add</mat-icon>
    Add Key
  </button>

  <table mat-table [dataSource]="keyData" #keyTable class="mat-elevation-z8 demo-table">
    <ng-container matColumnDef="active">
      <th mat-header-cell *matHeaderCellDef> Active </th>
      <td mat-cell *matCellDef="let element"> {{element.active}} </td>
    </ng-container>

    <ng-container matColumnDef="key-id">
      <th mat-header-cell *matHeaderCellDef> Key ID </th>
      <td mat-cell *matCellDef="let element"> {{element.key_id}} </td>
    </ng-container>

    <ng-container matColumnDef="description">
      <th mat-header-cell *matHeaderCellDef> Description </th>
      <td mat-cell *matCellDef="let element"> {{element.description}} </td>
    </ng-container>

    <ng-container matColumnDef="checkbox">
      <th mat-header-cell *matHeaderCellDef>
        <input type="checkbox">
      </th>
      <td mat-cell *matCellDef="let element"> </td>
    </ng-container>

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

Here's is the component:

@Component({
  selector: 'app-policies',
  standalone: true,
  imports: [CommonModule, MatCheckboxModule, MatIconModule, MatCardModule, MatTabsModule, FormsModule, MatFormFieldModule, MatInputModule, MatSidenavModule, MatTableModule],
  templateUrl: './policies.component.html',
  styleUrl: './policies.component.scss',
  changeDetection: ChangeDetectionStrategy.Default
})
export class PoliciesComponent {
  @ViewChild(MatTable) keyTable!: MatTable<any>;

  keyColmuns: string[] = ["active", "key-id", "description"]
  keyData: any = []

  constructor(
    private endpointService: EndpointService,
  ) { }

  onAddKey() {
    const newKeyId = Math.random().toString(36).slice(-10)

    this.endpointService.makeRequest({
      params: {
        key_id: newKeyId,
        policy_id: this.openedRow.policy_id,
      },
      method: "aaaaaaaaaaaa"
    },
      "aaaaaaaaaa"
    ).subscribe({
      next: (value: any) => {
        console.log('value', value)
        this.keyData.push({
          active: 1,
          api_set_key: value.result.api_set_key,
          description: "",
          key_id: newKeyId,
        })
        // A new row is being inserted here but this is not displayed in the UI until I refresh the page.
        this.keyTable.renderRows();
        console.log('this.keyData', this.keyData)
      },
      error: err => {
        console.error('Error:', err)
      },
    })

  }

I have also tried running detectChanges(); from ChangeDetectorRef and that hasn't worked either.


Solution

  • Could you please try making the below change, which creates a new reference to the array which might cause the reload of the grid.

    ...
    ).subscribe({
          next: (value: any) => {
            console.log('value', value)
            this.keyData.push({
              active: 1,
              api_set_key: value.result.api_set_key,
              description: "",
              key_id: newKeyId,
            })
            this.keyData = [...this.keyData]; // <-- changed here!
            // A new row is being inserted here but this is not displayed in the UI until I refresh the page.
            this.keyTable.renderRows();
            console.log('this.keyData', this.keyData)
          },
          error: err => {
            console.error('Error:', err)
          },
        })
    ...