0

table -> Action -> InActive

When we have changed the row status value, the mat-table data source value is also updated.

Our requirement is to change the status value after being updated to the database but now the mat-table immediately changes the status value.

How do we stop the mat-table Datasource update?

I have given the example. please see the stackblitz

HTML

<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
  <!--- Note that these columns can be defined in any order.
        The actual rendered columns are set as a property on the row definition" -->

  <!-- Position Column -->
  <ng-container matColumnDef="position">
    <th mat-header-cell *matHeaderCellDef>No.</th>
    <td mat-cell *matCellDef="let element">{{element.position}}</td>
  </ng-container>

  <!-- Name Column -->
  <ng-container matColumnDef="name">
    <th mat-header-cell *matHeaderCellDef>Name</th>
    <td mat-cell *matCellDef="let element">{{element.name}}</td>
  </ng-container>

  <!-- Weight Column -->
  <ng-container matColumnDef="weight">
    <th mat-header-cell *matHeaderCellDef>Weight</th>
    <td mat-cell *matCellDef="let element">{{element.weight}}</td>
  </ng-container>

  <!-- Symbol Column -->
  <ng-container matColumnDef="symbol">
    <th mat-header-cell *matHeaderCellDef>Symbol</th>
    <td mat-cell *matCellDef="let element">{{element.symbol}}</td>
  </ng-container>
  <ng-container matColumnDef="status">
    <th mat-header-cell *matHeaderCellDef>status</th>
    <td mat-cell *matCellDef="let element">{{element.status}}</td>
  </ng-container>
  <ng-container matColumnDef="actions">
    <th mat-header-cell *matHeaderCellDef>Actions</th>
    <td mat-cell *matCellDef="let element">
      <button
        mat-button
        [matMenuTriggerFor]="menu"
        class="nav-link dropdown-toggle mobile-data"
      >
        Acción
      </button>
      <mat-menu #menu="matMenu">
        <button
          mat-menu-item
          class="dropdown-item"
          (click)="updateStatus('inActive',element)"
        >
          <span>InActive</span>
        </button>
      </mat-menu>
    </td>
  </ng-container>
  <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
  <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>

ts

import { Component } from '@angular/core';

/**
 * @title Basic use of `<table mat-table>`
 */
@Component({
  selector: 'table-basic-example',
  styleUrls: ['table-basic-example.css'],
  templateUrl: 'table-basic-example.html',
})
export class TableBasicExample {
  displayedColumns = [
    'position',
    'name',
    'weight',
    'symbol',
    'status',
    'actions',
  ];
  dataSource = ELEMENT_DATA;
  updateStatus(status, item) {
    console.log('before set status', this.dataSource);
    item.status = status;
    console.log('After set status', this.dataSource);
  }
}

export interface PeriodicElement {
  name: string;
  position: number;
  weight: number;
  symbol: string;
  status: string;
}

const ELEMENT_DATA: PeriodicElement[] = [
  {
    position: 1,
    name: 'Hydrogen',
    weight: 1.0079,
    symbol: 'H',
    status: 'Active',
  },
  {
    position: 2,
    name: 'Helium',
    weight: 4.0026,
    symbol: 'He',
    status: 'Active',
  },
  {
    position: 3,
    name: 'Lithium',
    weight: 6.941,
    symbol: 'Li',
    status: 'Active',
  },
];

stackblitz demo: https://stackblitz.com/edit/angular-keucik?file=app/table-basic-example.ts

Murugan
  • 95
  • 2
  • 12
  • 1
    Hello Murugan. After answer you, we need more information. We need to see, when and where you are calling to de API Backend. – Guiditox Oct 29 '21 at 06:38
  • Just I am set item.status = status but the DataSource( [dataSource]="dataSource") value also changed. That my issue – Murugan Oct 29 '21 at 06:41
  • 1
    The code that you shared, is not showing that. If you need help, please provide the correct information – Guiditox Oct 29 '21 at 06:47
  • 1
    I have updated the stackblitz code. please check it – Murugan Oct 29 '21 at 06:58
  • updateStatus(status, item) { console.log('before set status', this.dataSource); item.status = status; console.log('After set status', this.dataSource); } – Murugan Oct 29 '21 at 06:59
  • why dataSource status value change after set item.status = status? – Murugan Oct 29 '21 at 06:59
  • did you understand my problem? – Murugan Oct 29 '21 at 07:03
  • Yes, I do. MatDataSource receives an array. In this case ELEMENT_DATA. When you click (click) = "updateStatus ('inActive', element)", you are passing the REFERENCE element of the array. It's like passing the element dataSource [k]. All two are the same, the same literal object. So when you change one of the attributes of one child of the array, you are modifying the source object and therefore the table, it is read correctly – Guiditox Oct 29 '21 at 07:08
  • element = dataSource[k] it's the reference, it isn't a new object. It's the same. So, if you change item.status, it's going to change on dataSource[k] – Guiditox Oct 29 '21 at 07:09
  • How to set item.status = status without datasource value change? – Murugan Oct 29 '21 at 07:11
  • 1
    I'm going to explain that in a answer – Guiditox Oct 29 '21 at 07:12

1 Answers1

1

The problem is that when you modify element, you are modifying the source code of your table. (datasource)

You will not be able to edit the value of an item, without modifying the table. But you can create an auxiliary array, to keep your new states.

Example

TS

import { Component } from '@angular/core';
import { MatTableDataSource } from '@angular/material';

/**
 * @title Basic use of `<table mat-table>`
 */
@Component({
  selector: 'table-basic-example',
  styleUrls: ['table-basic-example.css'],
  templateUrl: 'table-basic-example.html',
})
export class TableBasicExample {
  displayedColumns = [
    'position',
    'name',
    'weight',
    'symbol',
    'status',
    'actions',
  ];
  dataSource = ELEMENT_DATA;
  dataSourceAux = JSON.parse(JSON.stringify(ELEMENT_DATA));

  updateStatus(status, item) {
    const idx = this.dataSourceAux.findIndex((x) => x.name === item.name);
    this.dataSourceAux[idx].status = status;
    /**
     * or const itemAux = this.dataSourceAux.find((x) => x.name === item.name)
     * itemAux.status = status;
     *
     * Now you have two list, one with the real table values, and another with the copy of them
     * And what you should do, is change the value of the auxiliar list, not the real.
     * when you want to update the table, just do
     * this.dataSource = JSON.parse(JSON.stringify(this.dataSourceAux))
     */
  }
}

export interface PeriodicElement {
  name: string;
  position: number;
  weight: number;
  symbol: string;
  status: string;
}

/**  Copyright 2018 Google Inc. All Rights Reserved.
    Use of this source code is governed by an MIT-style license that
    can be found in the LICENSE file at http://angular.io/license */

const ELEMENT_DATA: PeriodicElement[] = [
  {
    position: 1,
    name: 'Hydrogen',
    weight: 1.0079,
    symbol: 'H',
    status: 'Active',
  },
  {
    position: 2,
    name: 'Helium',
    weight: 4.0026,
    symbol: 'He',
    status: 'Active',
  },
  {
    position: 3,
    name: 'Lithium',
    weight: 6.941,
    symbol: 'Li',
    status: 'Active',
  },
];

The code, it could be better and safely. But it's just an example.

Guiditox
  • 657
  • 4
  • 10