DEV Community

Tomasz Flis
Tomasz Flis

Posted on

Simple selection by Angular CDK

Description

In my recent projects, I had to implement a table with select all or single row functionality. Angular CDK library has SelectionModel, which makes that selection easy to implement.

Setup project

My project is using Angular, so I've created a new project (using Angular CLI) by typing in console:

ng new simple-selection
Enter fullscreen mode Exit fullscreen mode

My demo project is quite simple, so I answered "No" on routing and selected SCSS as my stylesheet format. To install Angular CDK, I typed in the project root:

npm i @angular/cli
Enter fullscreen mode Exit fullscreen mode

Additionally (not required), I used Bootstrap to have provided styling; I added it by typing:

npm i bootstrap
Enter fullscreen mode Exit fullscreen mode

In angular.json file, I added boostrap.scss import to projects.architect.build.options.styles so it looks now:

            "styles": [
              "src/styles.scss",
              "node_modules/bootstrap/scss/bootstrap.scss"
            ],
Enter fullscreen mode Exit fullscreen mode

Now my project is ready to develop a table with selection.

Selection

Typescript part

In app.component.scss I created some dummy variable with list of rows:

  rows: any[] = [
    { id: 1, name: 'test1', email: 'test1@test.com' },
    { id: 2, name: 'test2', email: 'test2@test.com' },
    { id: 3, name: 'test3', email: 'test3@test.com' },
    { id: 4, name: 'test4', email: 'test4@test.com' },
    { id: 5, name: 'test5', email: 'test5@test.com' },
  ];
Enter fullscreen mode Exit fullscreen mode

Next, I added variable with selection model from CDK:

selectionModel = new SelectionModel(true);
Enter fullscreen mode Exit fullscreen mode

The import for that model is:

import { SelectionModel } from '@angular/cdk/collections';
Enter fullscreen mode Exit fullscreen mode

Inside ngOnInit life cycle I subscribed to changes on selection (just for proof that selection is working):

  ngOnInit(): void {
    this.selectionModel.changed
      .pipe(pluck('source', 'selected'))
      .subscribe((selected) => console.log(selected));
  }
Enter fullscreen mode Exit fullscreen mode

selectionModel has property changed which emits selected data. pluck operator takes arguments to get (nested) property from emitted object.
To know if all rows are selected, I've made getter which compares length of rows with selected items lengt. If it returns with true then all rows are selected.

  get areAllSelected(): boolean {
    return this.rows.length === this.selectionModel.selected.length;
  }
Enter fullscreen mode Exit fullscreen mode

To select all rows, I am mapping them and adding each row to selection. To deselect all, I am using clear method from selectionModel.

  onSelectAllChange(): void {
    if (this.areAllSelected) {
      this.selectionModel.clear();
    } else {
      this.rows.map((row) => this.selectionModel.select(row));
    }
  }
Enter fullscreen mode Exit fullscreen mode

HTML part

HTML contains basic table from bootstrap documentation. There are two key elements:
header checkbox uses the areAllSelected property check state and the onSelectAllChange method to select or deselect all rows on the change event.
Second element is checkbox from row column. On change event it uses toggle method from selectionModel and pass current row. To know if checkbox should be checked it uses isSelected method from selectionModel and also passes current row. Full HTML code:

<table class="table">
  <thead>
    <tr>
      <th>
        <input
          class="form-check-input"
          type="checkbox"
          id="table-select-all"
          aria-label="Rows selection"
          (change)="onSelectAllChange()"
          [checked]="areAllSelected">
      </th>
      <th scope="col">ID</th>
      <th scope="col">Name</th>
      <th scope="col">Email</th>
    </tr>
  </thead>
  <tbody>
    <tr *ngFor="let row of rows; index as i">
      <td>
        <input
          class="form-check-input"
          type="checkbox"
          [id]="'row-checkbox-' + i"
          aria-label="Row selection"
          (change)="selectionModel.toggle(row)"
          [checked]="selectionModel.isSelected(row)">
      </td>
      <td>{{ row.id }}</td>
      <td>{{ row.name }}</td>
      <td>{{ row.email }}</td>
    </tr>
  </tbody>
</table>
Enter fullscreen mode Exit fullscreen mode

Link to repo.

Discussion (0)