Issue
I’m learning Angular and trying to grasp the concepts. I’m having difficulty doing something that should be simple.
I want to connect a Material Table to a service that downloads some data.
I created my service that downloads some simple data from a website. I created the Data Table using the command line. Now I must change the data source for my service.
Here is the generated file rank-table-datasource.ts
:
import { DataSource } from '@angular/cdk/collections';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { map } from 'rxjs/operators';
import { Observable, of as observableOf, merge } from 'rxjs';
// TODO: Replace this with your own data model type
export interface RankTableItem {
name: string;
id: number;
}
// TODO: replace this with real data from your application
const EXAMPLE_DATA: RankTableItem[] = [
{id: 1, name: 'Hydrogen'},
{id: 2, name: 'Helium'},
{id: 3, name: 'Lithium'},
{id: 4, name: 'Beryllium'},
{id: 5, name: 'Boron'},
{id: 6, name: 'Carbon'},
{id: 7, name: 'Nitrogen'},
{id: 8, name: 'Oxygen'},
{id: 9, name: 'Fluorine'},
{id: 10, name: 'Neon'},
{id: 11, name: 'Sodium'},
{id: 12, name: 'Magnesium'},
{id: 13, name: 'Aluminum'},
{id: 14, name: 'Silicon'},
{id: 15, name: 'Phosphorus'},
{id: 16, name: 'Sulfur'},
{id: 17, name: 'Chlorine'},
{id: 18, name: 'Argon'},
{id: 19, name: 'Potassium'},
{id: 20, name: 'Calcium'},
];
/**
* Data source for the RankTable view. This class should
* encapsulate all logic for fetching and manipulating the displayed data
* (including sorting, pagination, and filtering).
*/
export class RankTableDataSource extends DataSource<RankTableItem> {
data: RankTableItem[] = EXAMPLE_DATA;
paginator: MatPaginator;
sort: MatSort;
constructor() {
super();
}
/**
* Connect this data source to the table. The table will only update when
* the returned stream emits new items.
* @returns A stream of the items to be rendered.
*/
connect(): Observable<RankTableItem[]> {
// Combine everything that affects the rendered data into one update
// stream for the data-table to consume.
const dataMutations = [
observableOf(this.data),
this.paginator.page,
this.sort.sortChange
];
return merge(...dataMutations).pipe(map(() => {
return this.getPagedData(this.getSortedData([...this.data]));
}));
}
/**
* Called when the table is being destroyed. Use this function, to clean up
* any open connections or free any held resources that were set up during connect.
*/
disconnect() {}
/**
* Paginate the data (client-side). If you're using server-side pagination,
* this would be replaced by requesting the appropriate data from the server.
*/
private getPagedData(data: RankTableItem[]) {
const startIndex = this.paginator.pageIndex * this.paginator.pageSize;
return data.splice(startIndex, this.paginator.pageSize);
}
/**
* Sort the data (client-side). If you're using server-side sorting,
* this would be replaced by requesting the appropriate data from the server.
*/
private getSortedData(data: RankTableItem[]) {
if (!this.sort.active || this.sort.direction === '') {
return data;
}
return data.sort((a, b) => {
const isAsc = this.sort.direction === 'asc';
switch (this.sort.active) {
case 'name': return compare(a.name, b.name, isAsc);
case 'id': return compare(+a.id, +b.id, isAsc);
default: return 0;
}
});
}
}
/** Simple sort comparator for example ID/Name columns (for client-side sorting). */
function compare(a: string | number, b: string | number, isAsc: boolean) {
return (a < b ? -1 : 1) * (isAsc ? 1 : -1);
}
I imported my service and my interface:
import { EscolaService } from '../escola.service'
import { Escola } from '../escola';
My Interface also has just an id
and a name
, like the original.
Defined an alias for my type. Don’t know if this is the correct way:
export type RankTableItem = Escola;
I should now redefine the connect()
method:
connect(): Observable<RankTableItem[]> {
but I don’t know how to do it.
The rank-table-component.html
tries to use some dataSource methods:
<mat-paginator #paginator
[length]="dataSource?.data.length"
[pageIndex]="0"
[pageSize]="50"
[pageSizeOptions]="[25, 50, 100, 250]">
How should I use this connect method and the Observer generated by my Service?
Solution
You can use your own datasource like below
a. This is your custom datasource that you defined.
export class RankTableDataSource extends DataSource<RankTableItem> {
//Your rest of the code with connect() and disconnect() methods.
}
b. Then you can consume the above data source in your component like
export class YourComponent implements OnInit, AfterViewInit {
//Take your data source into data bound property
dataSource: RankTableDataSource;
constructor( ) {}
//Initialize your data source in onInit method
ngOnInit() {
this.dataSource = new RankTableDataSource();
}
}
c. Then use this dataSource
into your template.
The connect()
and disconnect()
methods automatically invoked by mat-table data source. You don’t need to manually called those methods into your own code if you used custom data source.