This is my hobby project and it has been stuck due of this issue for some time. It might be an easy issue, but my knowledge about Angular and JS is rather limited.. Nevertheless my code is below (I have shorten it a bit) and it is working to some extent. It is fetching data from server and then it is displayed at client. No issues there, but now when I am trying to do client side filtering then nothing happens. Literally. I am typing into filter input box and nothing. Table rows are not filtered.
I am wondering here two things:
MyData.ts
export interface MyData {
id: number;
description: string;
}
MyData.service.ts
export class MyService {
constructor(private http: HttpClient) { }
getData(): Observable<MyData[]> {
return this.http.get...
}
}
MyData.datasource.ts
export class MyDataSource extends MatTableDataSource<MyData> {
private mySubject = new BehaviorSubject<MyData[]>([]);
constructor(private myService: MyService) { super(); }
loadData() {
this.myService.getData()
.pipe(catchError(() => of([])))
.subscribe(data => this.mySubject.next(data));
}
connect(): BehaviorSubject<myData[]> {
return this.mySubject;
}
disconnect(): void {
this.mySubject.complete();
}
}
MyData.component.ts
export class MyDataComponent implements OnInit {
displayedColumns= ["id", "description"];
dataSource: MyDataSource;
constructor(private myService: MyService) { }
ngOnInit() {
this.dataSource = new MyDataSource(this.myService);
this.dataSource.loadData();
}
applyFilter(filterValue: string) {
this.dataSource.filter = filterValue.trim().toLowerCase();
}
}
MyData.component.html
<mat-form-field>
<input matInput (keyup)="applyFilter($event.target.value)" placeholder="Filter">
</mat-form-field>
<mat-table [dataSource]="dataSource">
<ng-container matColumnDef="id">
<mat-header-cell *matHeaderCellDef>ID</mat-header-cell>
<mat-cell *matCellDef="let data">{{data.id}}</mat-cell>
</ng-container>
<ng-container matColumnDef="description">
<mat-header-cell *matHeaderCellDef>Description</mat-header-cell>
<mat-cell *matCellDef="let data">{{data.description}}</mat-cell>
</ng-container>
</mat-table>
MatColumnDef extends CdkColumnDefDefines a set of cells available for a table column.
A <mat-cell> element which contains the content of the cell. The directive *matCellDef needs to be applied here and the string let user is assigned. By assigning that string we're making sure that we're able to access the current item from the data source via user.
Yes you can extend data source if you want to have more control over your data for example custom sorting, filtering, pagination and real time streaming/manipulation of data. If not you can just use the default data source class provided in the material website
https://material.angular.io/components/table/overview
As stated in the material site above you can extend the datasource class if you want to do more complex stuff
Advanced data sources
The simplest way to provide data to your table is by passing a data array. More complex use-cases may benefit from a more flexible approach involving an Observable stream or by encapsulating your data source logic into a DataSource class.
Here is a more complex example on how you can use it.
The below code is the constructor of the datasource. Which takes in the paginator, dataservice and Mat sort.
constructor(public _dataService: DataService,
public _paginator: MatPaginator,
public _sort: MatSort) {
super();
// Reset to the first page when the user changes the filter.
this._filterChange.subscribe(() => this._paginator.pageIndex = 0);
}
Then you will implement the connect class. This connect class is an observable where your mat-table will subcribe to this observable and display data accordingly to what the observable returns
connect(): Observable<Array<Data>> {
// Listen for any changes in the base data, sorting, filtering, or
//pagination the below object types are all observable/behaviour
//subjects
const displayDataChanges = [
this._dataService.entryDataChange,
this._sort.sortChange,
this._filterChange,
this._paginator.page
];
data: YourCurrentData;
// Merge all the observable into one stream
return Observable.merge(...displayDataChanges).map((n) => {
// If is filter data observer do action
// If is a sort observer emitting data do action
// If is new incoming data do action
// If is a paginator observable emmiting data do action
// Return filtered, sorted, and paged data that you want to display
// on your current page.
});
}
The above example uses the old rxjs version. But hope you get the logic behind it!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With