Hide-show or add-remove columns dynamically in angular material table


  Hi, in any application we mostly show the data in tabular format and user like that data handling, if we provide them multiple options to view the data. like in our one of the previous posts (click here to go to the post) we have seen how to add pagination, searching and sorting etc to the angular material table so the user can use that according to his need.
  In this post, we are going to add one more feature to our angular material table that is, hide/show columns dynamically or we also can say add/remove columns dynamically. We are going to do that in angular purely, we are not going to install any third-party plugin or library. Let’s do it.

[If you have any problem related to the Angular material table please check our following posts:
Click here for a simple material table with searching, sorting, and pagination,
Click here for inline editing and validation with template-driven forms in the angular material table,
Click here for multiple expandable rows in the angular material table,
Click here for a table inside a row and multiple paginators in the angular material table
Click here for adding custom and common filter/search in the angular material table]


following is the HTML file of our angular component, in this we have added angular material table and added some basic features like pagination searching sorting. Just above the table, we have added a material menu to show the list of columns that we are having in our table and we have provided the slide toggle-button to hide/show the column.

<div class="body">
    <div class="row">
        <div class="text-center col-lg-12">
            <h4 class="form-control">Angular - Dynamically hide-show or add-remove columns in angular material table
            </h4>
        </div><br><br>
    </div>
    <div class="row">
        <div class="col-lg-2"></div>
        <div class="col-lg-8 center">
            <div class="spinner-container" *ngIf="userListMatTabDataSource.loading$ | async">
                <mat-spinner></mat-spinner>
            </div>
            <div class="card">
                <div class="thead">
                    <label for="Table">Demo Table</label>
                    <button style="float:right" class="btn btn-sm btn-primary top-margin" #menuTrigger="matMenuTrigger"
                        [matMenuTriggerFor]="mainMenuButton">
                        hide/show
                    </button>
                    <mat-menu #mainMenuButton="matMenu">
                        <span (click)="$event.stopPropagation()" *ngFor="let column of columnShowHideList;index as i">
                            <mat-slide-toggle [(ngModel)]="column.isActive" (change)="toggleColumn(column)">
                            </mat-slide-toggle>
                            {{column.name}}
                            <br>
                        </span>
                    </mat-menu>
                    <input type="text" style="float:right" (keyup)="applyFilter($event.target.value)"
                        placeholder="search for" class="form-control-sm top-margin">
                </div>
                <mat-table class="mat-elevation-z8" [dataSource]="userListMatTabDataSource" matSort
                    matSortActive="userName" matSortDirection="asc" matSortDisableClear>
                    <ng-container matColumnDef="srno">
                        <mat-header-cell *matHeaderCellDef>Sr No</mat-header-cell>
                        <mat-cell *matCellDef="let user; let i = index;">
                            {{i+1}}
                        </mat-cell>
                    </ng-container>
                    <ng-container matColumnDef="userName">
                        <mat-header-cell *matHeaderCellDef mat-sort-header>User Name</mat-header-cell>
                        <mat-cell *matCellDef="let user">
                            {{user.userName}}
                        </mat-cell>
                    </ng-container>
                    <ng-container matColumnDef="email">
                        <mat-header-cell *matHeaderCellDef mat-sort-header>Email</mat-header-cell>
                        <mat-cell *matCellDef="let user">
                            {{user.email}}
                        </mat-cell>
                    </ng-container>
                    <ng-container matColumnDef="contactNo">
                        <mat-header-cell *matHeaderCellDef mat-sort-header>Contact No</mat-header-cell>
                        <mat-cell *matCellDef="let user">
                            {{user.contactNo}}
                        </mat-cell>
                    </ng-container>
                    <ng-container matColumnDef="address">
                        <mat-header-cell *matHeaderCellDef mat-sort-header>Address</mat-header-cell>
                        <mat-cell *matCellDef="let user">
                            {{user.address}}
                        </mat-cell>
                    </ng-container>
                    <mat-header-row *matHeaderRowDef="columnList"></mat-header-row>
                    <mat-row *matRowDef="let row; columns: columnList; let i = index;"
                        [class.selected]="selectedRow == row.id" (click)="rowClick(row.id)">
                    </mat-row>
                </mat-table>
                <mat-paginator [pageSizeOptions]="[3, 5, 10]" showFirstLastButtons></mat-paginator>
            </div>
        </div>
    </div>
</div>


After HTML let’s see the typescript file.  Here we have done all basic things to show data and add paginator, searching, sorting in the angular material table and what additional we have done is, we have added one extra array to hold hide/show status of the column. While storing status we also need to store the position of the column so when we are going to add/show column again, we can show it to the original position. After that, we have added all columns with other needed data in that extra array, in initializeColumnProperties function. Once everything is set we have added toggleColumn function to hide/show columns, in that function, we have checked if toggle slide is false then simply remove the column from the material table and if it is true then check for the position and push the column to the particular position.
The following code will make you understand everything.

import { ComponentViewChildOnInit } from '@angular/core';
import { User } from './user/User';
import { MatTableDataSourceMatPaginatorMatSort } from '@angular/material';

interface CustomColumn {
  possitionnumber;
  namestring;
  isActiveboolean;
}

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})

export class AppComponent implements OnInit {

  userListUser[];
  selectedRownumber;
  editedRowsboolean[];
  public columnList = ['srno''userName''email''contactNo''address'];
  public columnShowHideListCustomColumn[] = [];

  userListMatTabDataSource = new MatTableDataSource<User>(this.userList);

  @ViewChild(MatPaginatorpaginatorMatPaginator;
  @ViewChild(MatSortsortMatSort;

  constructor() { }

  ngOnInit() {
    this.initializeColumnProperties();
    this.editedRows = [];
    this.getAlldata();
    console.log(this.userList);
    this.userListMatTabDataSource.paginator = this.paginator;
    this.userListMatTabDataSource.sort = this.sort;
  }

  applyFilter(filterValuestring) {
    this.userListMatTabDataSource.filter = filterValue.trim().toLowerCase();
  }

  toggleColumn(column) {
    if (column.isActive) {
      if (column.possition > this.columnList.length - 1) {
        this.columnList.push(column.name);
      } else {
        this.columnList.splice(column.possition0column.name);
      }
    } else {
      let i = this.columnList.indexOf(column.name);
      let opr = i > -1 ? this.columnList.splice(i1) : undefined;
    }
  }

  initializeColumnProperties() {
    this.columnList.forEach((elementindex=> {
      this.columnShowHideList.push(
        { possition: indexname: elementisActive: true }
      );
    });
    // After for loop it will look like this
    //   public columnShowHideList = [
    //   { possition: 0, name: 'action', isActive: true },
    //   { possition: 1, name: 'userName', isActive: true },
    //   { possition: 2, name: 'email', isActive: true },
    //   { possition: 3, name: 'contactNo', isActive: true },
    //   { possition: 4, name: 'address', isActive: true }
    // ];
  }

  getAlldata() {
    this.userList = [
      {
        id: 1userName: 'Ramesh'password: 'rebqwtye'email: 'ramesh@gmail.com',
        contactNo: '9788235466'address: '123 RG Road, XYCity'edited: undefined
      },
      {
        id: 2userName: 'Suresh'password: 'rebqwtye'email: 'suresh@gmail.com',
        contactNo: '9788235466'address: '123 RG Road, XYCity'edited: undefined
      },
      {
        id: 3userName: 'Ganesh'password: 'rebqwtye'email: 'ganesh@gmail.com',
        contactNo: '9788235466'address: '123 RG Road, XYCity'edited: undefined
      },
      {
        id: 4userName: 'Bhavesh'password: 'rebqwtye'email: 'bhavesh@gmail.com',
        contactNo: '9788235466'address: '123 RG Road, XYCity'edited: undefined
      },
      {
        id: 5userName: 'Bhavesh'password: 'rebqwtye'email: 'bhavesh@gmail.com',
        contactNo: '9788235466'address: '123 RG Road, XYCity'edited: undefined
      },
      {
        id: 6userName: 'Bhavesh'password: 'rebqwtye'email: 'bhavesh@gmail.com',
        contactNo: '9788235466'address: '123 RG Road, XYCity'edited: undefined
      },
      {
        id: 7userName: 'Bhavesh'password: 'rebqwtye'email: 'bhavesh@gmail.com',
        contactNo: '9788235466'address: '123 RG Road, XYCity'edited: undefined
      }
    ];
    this.userListMatTabDataSource.data = this.userList;
  }

  rowClick(rowId) {
    this.selectedRow = rowId;
  }
}

export class User {
    idNumber;
    userNameString;
    passwordString;
    emailString;
    contactNoString;
    addressString;
    editedBoolean;

    constructor() { };
}

Above is the model or type to hold the user data and to assign it to the material table.

We have not imported anything out of the angular library, here is the module file.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { FormsModule } from '@angular/forms';
import {
  MatTableModule,
  MatPaginatorModule,
  MatProgressSpinnerModule,
  MatFormFieldModule,
  MatInputModule,
  MatSortModule,
  MatButtonModule,
  MatMenuModule,
  MatSlideToggleModule
from '@angular/material';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule,
    MatTableModule,
    MatPaginatorModule,
    MatProgressSpinnerModule,
    MatInputModule,
    MatButtonModule,
    MatFormFieldModule,
    BrowserAnimationsModule,
    MatSortModule,
    MatMenuModule,
    MatSlideToggleModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }


Output




And that’s it, 


Hope you like it.

Here you can download the project Click here to download the project

When you download the project, at the very first run command “npm install”.
Because of the size issue, we are not going to upload the node module folder onwards.

Comments

  1. Link to download all your examples is broken?

    ReplyDelete
  2. Can you provide a demo so that it gets clear what it's exactly what users want

    ReplyDelete
    Replies
    1. if you click on "Click here to download the project" you will get the project

      Delete
  3. I have built and ran this example, but it shows error in line userListMatTabDataSource = new MatTableDataSource(this.userList);

    src/app/reporting/demo/demo.component.ts:22:3
    22 userList: User[];
    ~~~~~~~~
    'userList' is declared here.

    ReplyDelete

Post a Comment