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
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
Additionally (not required), I used Bootstrap to have provided styling; I added it by typing:
npm i bootstrap
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"
],
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' },
];
Next, I added variable with selection model from CDK:
selectionModel = new SelectionModel(true);
The import for that model is:
import { SelectionModel } from '@angular/cdk/collections';
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));
}
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;
}
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));
}
}
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>
Link to repo.
Top comments (0)