Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<ng-container [formGroup]="vehicleFilterForm">
<sbb-table-wrapper>
<table sbb-table>
<ng-container sbbColumnDef="select">
<th sbb-header-cell *sbbHeaderCellDef style="width: 50px">
<sbb-checkbox
(change)="$event ? masterToggle() : null"
[checked]="selection.hasValue() && isAllSelected()"
[indeterminate]="selection.hasValue() && !isAllSelected()"
[aria-label]="checkboxLabel()"
>
</sbb-checkbox>
</th>
<td sbb-cell *sbbCellDef="let row">
<sbb-checkbox
(click)="$event.stopPropagation()"
(change)="$event ? selection.toggle(row) : null"
[checked]="selection.isSelected(row)"
[aria-label]="checkboxLabel(row)"
>
</sbb-checkbox>
</td>
</ng-container>
<ng-container *ngFor="let column of columns.slice(1)" [sbbColumnDef]="column">
<th sbb-header-cell *sbbHeaderCellDef style="width: 20%">{{ column }}</th>
<td sbb-cell *sbbCellDef="let element">{{ element[column] }}</td>
</ng-container>

<ng-container sbbColumnDef="filter-name">
<th sbb-header-cell *sbbHeaderCellDef class="sbb-table-filter">
<input class="sbb-input-element" formControlName="name" />
</th>
</ng-container>
<ng-container sbbColumnDef="filter-description">
<th sbb-header-cell *sbbHeaderCellDef class="sbb-table-filter">
<input class="sbb-input-element" formControlName="description" />
</th>
</ng-container>
<ng-container sbbColumnDef="filter-category">
<th sbb-header-cell *sbbHeaderCellDef class="sbb-table-filter">
<sbb-select formControlName="category" multiple placeholder="Select category...">
<sbb-option *ngFor="let category of categories" [value]="category"
>{{ category }}</sbb-option
>
</sbb-select>
</th>
</ng-container>

<ng-container sbbColumnDef="empty">
<th sbb-header-cell *sbbHeaderCellDef></th>
</ng-container>

<tr sbb-header-row *sbbHeaderRowDef="columns"></tr>
<tr
sbb-header-row
*sbbHeaderRowDef="['empty', 'empty', 'filter-name', 'empty', 'filter-description', 'filter-category']"
></tr>
<tr sbb-row *sbbRowDef="let row; columns: columns"></tr>
</table>
</sbb-table-wrapper>

<p *ngIf="dataSource.filteredData.length === 0">No keywords match your filters.</p>

<sbb-paginator class="sbb-divider-small-top" [pageSize]="5"></sbb-paginator>
</ng-container>

<h4>Selected Models</h4>
<sbb-checkbox [formControl]="includeFilteredCtrl">Include filtered out data</sbb-checkbox>
<pre>{{ selectedData | json }}</pre>
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
import { SelectionModel } from '@angular/cdk/collections';
import { AfterViewInit, Component, OnDestroy, ViewChild } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
import { SbbPaginator } from '@sbb-esta/angular/pagination';
import { SbbTable, SbbTableDataSource, SbbTableFilter } from '@sbb-esta/angular/table';
import { merge, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

interface VehicleExampleItem {
position: number;
name: string;
category: 'Trainset' | 'Locomotive' | 'Railcar';
power: number;
description: string;
}

interface VehicleFilter extends SbbTableFilter {
category?: string[] | null;
name?: string | null;
description?: string | null;
}

/**
* @title Table with filtering and selection
* @order 130
*/
@Component({
selector: 'sbb-filter-select-table-example',
templateUrl: 'filter-select-table-example.html',
})
export class FilterSelectTableExample implements AfterViewInit, OnDestroy {
@ViewChild(SbbPaginator) paginator: SbbPaginator;
@ViewChild(SbbTable) table: SbbTable<VehicleExampleItem>;

columns = ['select', 'position', 'name', 'power', 'description', 'category'];
dataSource = new SbbTableDataSource<VehicleExampleItem, VehicleFilter>(VEHICLE_EXAMPLE_DATA);
selection = new SelectionModel<VehicleExampleItem>(true, []);
selectedData: VehicleExampleItem[] = [];
categories = new Set(
VEHICLE_EXAMPLE_DATA.map((vehicleExampleItem) => vehicleExampleItem.category)
);

vehicleFilterForm = new FormGroup({
category: new FormControl([] as string[]),
name: new FormControl(''),
description: new FormControl(''),
});

includeFilteredCtrl = new FormControl(true);

private _destroyed = new Subject<void>();

/** Whether the number of selected elements matches the total number of rows. */
isAllSelected() {
const numSelected = this.selection.selected.length;
const numRows = this.dataSource.filteredData.length;
return numSelected >= numRows;
}

ngAfterViewInit() {
this.dataSource.paginator = this.paginator;
this.table.dataSource = this.dataSource;
this.vehicleFilterForm.valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe((vehicleFilterForm) => {
this.dataSource.filter = vehicleFilterForm;
this.updateSelectedData();
});

merge(this.selection.changed, this.includeFilteredCtrl.valueChanges)
.pipe(takeUntil(this._destroyed))
.subscribe(() => this.updateSelectedData());
}

/** Selects all rows if they are not all selected; otherwise clear selection. */
masterToggle() {
this.isAllSelected()
? this.selection.clear()
: this.dataSource.filteredData.forEach((row) => this.selection.select(row));
}

/** Updates the list of selected data */
updateSelectedData() {
this.selectedData = this.selection.selected.filter(
(item) => this.includeFilteredCtrl.value || this.dataSource.filteredData.includes(item)
);
}

/** The label for the checkbox on the passed row */
checkboxLabel(row?: VehicleExampleItem): string {
if (!row) {
return `${this.isAllSelected() ? 'select' : 'deselect'} all`;
}
return `${this.selection.isSelected(row) ? 'deselect' : 'select'} row ${row.position + 1}`;
}

ngOnDestroy(): void {
this._destroyed.next();
}
}

const VEHICLE_EXAMPLE_DATA: VehicleExampleItem[] = [
{
position: 1,
category: 'Railcar',
name: 'Bem 550',
power: 0,
description: 'Gleichstromfahrzeug 1500 V',
},
{
position: 2,
category: 'Trainset',
name: 'RABDe 510',
power: 2444,
description: '«Mirage», «Goldküstenexpress»',
},
{
position: 3,
category: 'Trainset',
name: 'RABDe 500',
power: 5200,
description: 'InterCity-Neigezug (ICN)',
},
{
position: 4,
category: 'Trainset',
name: 'RABe 511',
power: 4000,
description: 'KISS, RV-Dosto',
},
{ position: 5, category: 'Trainset', name: 'RABe 501', power: 6000, description: 'Giruno' },
{
position: 6,
category: 'Trainset',
name: 'RABDe 502',
power: 7500,
description: 'Twindexx IC 200, FV-Dosto',
},
{ position: 7, category: 'Trainset', name: 'ETR 610', power: 5500, description: 'Astoro' },
{
position: 8,
category: 'Trainset',
name: 'RABe 514',
power: 3200,
description: 'S-Bahn Zürich Doppelstocktriebzug (DTZ)',
},
{ position: 9, category: 'Trainset', name: 'RABe 520', power: 760, description: 'Seetal GTW' },
{ position: 10, category: 'Trainset', name: 'RABe 526', power: 1100, description: 'GTW' },
{ position: 11, category: 'Trainset', name: 'RABe 521', power: 2000, description: 'Flirt' },
{
position: 12,
category: 'Railcar',
name: 'RAe 591',
power: 835,
description: 'Churchill-Pfeil',
},
{ position: 13, category: 'Trainset', name: 'TGV PSE', power: 6450, description: 'TGV' },
{ position: 14, category: 'Trainset', name: 'TGV POS', power: 9200, description: 'TGV' },
{ position: 15, category: 'Trainset', name: 'RABe 591', power: 2310, description: 'TEE' },
{ position: 16, category: 'Railcar', name: 'RBe 4/4', power: 1988, description: 'RBe' },
{ position: 17, category: 'Railcar', name: 'RBDe 4/4', power: 1650, description: 'NPZ' },
{ position: 18, category: 'Railcar', name: 'RAe 2/4', power: 404, description: 'Roter Pfeil' },
{ position: 19, category: 'Locomotive', name: 'Re 420', power: 4700, description: 'Re 4/4 II' },
{
position: 20,
category: 'Locomotive',
name: 'Re 460',
power: 6100,
description: 'Locomotive 2000',
},
];
3 changes: 3 additions & 0 deletions src/components-examples/angular/table/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { SbbPaginationModule } from '@sbb-esta/angular/pagination';
import { SbbRadioButtonModule } from '@sbb-esta/angular/radio-button';
import { SbbSelectModule } from '@sbb-esta/angular/select';
import { SbbTableModule } from '@sbb-esta/angular/table';
import { FilterSelectTableExample } from '@sbb-esta/components-examples/angular/table/filter-select-table/filter-select-table-example';

import { ButtonsInTableExample } from './buttons-in-table/buttons-in-table-example';
import { CellActionsTableExample } from './cell-actions-table/cell-actions-table-example';
Expand Down Expand Up @@ -39,6 +40,7 @@ export {
SortableTableExample,
StickyTableExample,
ExpandableTableExample,
FilterSelectTableExample,
};

const EXAMPLES = [
Expand All @@ -54,6 +56,7 @@ const EXAMPLES = [
SortableTableExample,
StickyTableExample,
ExpandableTableExample,
FilterSelectTableExample,
];

@NgModule({
Expand Down