4

I have a mat-table that is viewed by 3 users of different roles. The table has multiple columns; one of the columns is active (a boolean value that controls the activation and deactivation of the account). I want to toggle that value with a switch within the same table (in another column), but only if the user is an admin.

I already achieved this using bootstrap table this way:

<table class="table table-striped">
    <thead>
        <tr>
            <th *ngIf="isAdmin(currentUser)" (click)="sortByAccountStatus()">
                <a>Deactivate/Activate</a>
                <a class="sort-by"></a>
            </th>
        </tr>
    </thead>
    <tbody>
        <tr *ngFor="let chartOfAccounts of accountList.reverse();" [hidden]="currentUser.role !== '1'">
            <td [hidden]="!chartOfAccounts.accountActive">
                <a (click)="deactivateAccount(chartOfAccounts)" class="text-danger">Deactivate</a>
            </td>
            <td [hidden]="chartOfAccounts.accountActive">
                <a (click)="activateAccount(chartOfAccounts)" class="text-danger">Activate</a>
            </td>
        </tr>
    </tbody>

    <tbody>
        <tr *ngFor="let chartOfAccounts of accountList" [hidden]="currentUser.role === '1'">
            <td>{{accountActiveStatus(chartOfAccounts.accountActive)}}</td>
        </tr>
    </tbody>
</table>

The code above will add a column to the table where the admin can click on activate or deactivate depending on the value of the boolean. The operations are implemented in the component.

Using mat-table, I got the boolean active column to work.

<ng-container matColumnDef="accountActive">
    <mat-header-cell *matHeaderCellDef mat-sort-header>Active</mat-header-cell>
    <mat-cell *matCellDef="let chartOfAccounts"> {{chartOfAccounts.accountActive}} </mat-cell>
</ng-container>

My goal is to create another column that holds the switch back and forth from true to false like this

<ng-container matColumnDef="activation">
    <mat-header-cell *matHeaderCellDef mat-sort-header>Activate/Deactivate</mat-header-cell>
    <mat-cell *matCellDef="let chartOfAccounts" [hidden]="!chartOfAccounts.accountActive">
        <a (click)="deactivateAccount(chartOfAccounts)" class="text-danger">Deactivate</a>
    </mat-cell>
    <mat-cell *matCellDef="let chartOfAccounts" [hidden]="chartOfAccounts.accountActive">
          <a (click)="activateAccount(chartOfAccounts)" class="text-danger">Deactivate</a>
    </mat-cell>
</ng-container>

This is not working and produces a weird result where when the toggle is switched off it cannot be switched back on again, the link disappears, and the toggle column too. Here is a screenshot.

screenshot

The boolean values are pushed to the right of the tables whenever they're switched to false

Updated:

Here is a stackblitz example. The toggle does not work but basically when you click on toggle the value of active should switch between true and false depending on if the toggle is on or off.

nash11
  • 8,220
  • 3
  • 19
  • 55
capuche
  • 55
  • 1
  • 6
  • Can you please create a stackblitz for the same? – Sudipto Mukherjee Sep 28 '19 at 09:22
  • The screenshot doesn't seem consistent with your code. Your code shows that the header's name is `Activate/Deactivate` while the screenshot shows `toggle` – nash11 Sep 28 '19 at 09:46
  • If you want not show a column you only need change the array `displayedColumns` -the variable you use in the tags `` and `` – Eliseo Sep 28 '19 at 10:09
  • @Eliseo thank you eliseo i though i can use [hidden] on the mat-cell, but you response make total sense, tried it and it works – capuche Sep 28 '19 at 10:20

3 Answers3

2

The reason your code isn't working is that you can't use two mat-cell in a mat-column. The second one will be ignored completely. This is why your table gets all messed up because on some cells the hidden is hiding the only cell present in that column (since the second cell is out of the picture).

You shouldn't be using two separate cells for this. You want Activate/Deactivate to appear in the same cell. So instead of using hidden on the mat-cell, use ngIf on the anchor tags to conditionally show Activate/Deactivate.

<ng-container matColumnDef="activation">
    <mat-header-cell *matHeaderCellDef mat-sort-header>Activate/Deactivate</mat-header-cell>
    <mat-cell *matCellDef="let chartOfAccounts">
        <a *ngIf="chartOfAccounts.accountActive" (click)="deactivateAccount(chartOfAccounts)" class="text-danger">Deactivate</a>
        <a *ngIf="!chartOfAccounts.accountActive" (click)="activateAccount(chartOfAccounts)" class="text-danger">Activate</a>
    </mat-cell>
</ng-container>

Edit: (after comments)

If you don't want to show a particular column, just remove it from the displayed columns, this way it won't be rendered by mat-table.

allColumns: string[] = ['position', 'name', 'weight', 'symbol', 'activate', 'toggle'];

checkIfAdmin() {
    this.displayedColumns = this.isAdmin ? this.allColumns : this.allColumns.filter(column => column !== 'toggle');
}

Here is a working example on StackBlitz.

nash11
  • 8,220
  • 3
  • 19
  • 55
  • one question though, can i add a directive to the ng-container, so that if the user is not and admin than the column should not be displayed `* normally the ngIf should be on the header so but i dont know if that will work too – capuche Sep 28 '19 at 10:27
  • @capuche I have updated my answer and added a working example. Use the `Toggle Admin` button in the example to check what an admin sees and otherwise – nash11 Sep 28 '19 at 10:57
0

As per my understanding your button/link is dependent on the value of active or inactive. So you can put 2 anchor tags in a cell and display it based on the value of active column

<ng-container matColumnDef="toggle">
    <th mat-header-cell *matHeaderCellDef> Toggle </th>
    <td mat-cell *matCellDef="let element">
      <a *ngIf="element.active === false" (click)="toggle(element.position)">Activate</a>
      <a *ngIf="element.active === true" (click)="toggle(element.position)">Deactivate</a>
    </td>
  </ng-container>

As you can see onclick is handled by a single function where I am passing an ID value (unique identifier of that row) and changing the active value on its click

toggle(position) {
    this.dataSource.find( d=> d.position === position).active = !this.dataSource.find( d=> d.position === position).active;
  }

Working Demo: https://stackblitz.com/edit/angular-ne15tp

Note: Please feel free to improve the performance of the code as this is just a dummy implementation for demo purpose

  • one more think, since this is viewed by users with different roles and only the admin can perform this action, where would you add the check to say `[hidden]="currentUser.role === '1'"` or `*ngIf="isAdmin(currentUser)"` this seems to work for admin but then when i log in as a regular user its not hidden – capuche Sep 28 '19 at 10:47
  • I have updated the stackblitz accordingly. Please check it. If it solves your problem mark it as answer. Happy Coding :) – Sudipto Mukherjee Sep 28 '19 at 10:57
0
<ng-container matColumnDef="Status">
    <th mat-header-cell *matHeaderCellDef mat-sort-header>Status</th>
     <td mat-cell *matCellDef="let row">
     <mat-slide-toggle
          [matTooltip]="row.active? 'Deactivate': 'Activate'"
          [checked]="row.ativo"
          (change)="updateStatusAccount(row.id, $event)">
      </mat-slide-toggle>
    </td>
</ng-container>
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Mar 09 '22 at 06:45