Proposal: Add detailed documentation for using DataSource with Material Table. Current documentation on DataSource is very high level. Tutorial level documentation, starting with basic table, then adding sort and paging would be good.
Level of documentation to make using Mat-Table and DataSources, along with Observables more developer friendly.
Very minimal level of documentation regarding how DataSources work with Mat-Table, pagination, and observables.
Have an AngularJS developer add a Mat-Table to a seed project, and use DataSource, Observable, http.get(), and pagination/sorting on the table. Documentation seems lacking to do this. A tutorial would be great.
Make Angular (4) more accessible to developers for a popular use case (full featured DataTable).
Latest Angular 4
+100
To add to this, I've gotten everything to work except for updating the datatable's dataSource with new data from a service. This is mostly an RxJS, Observable related question.
A real-world use case for this would be a search input where users can search and endpoint, return an array of results, and refresh the datatable - in 2 days I can't figure out how to make this work.
datatable.component.ts
@Component({
selector: 'mat-datatable',
styleUrls: ['./datatable.component.scss'],
templateUrl: './datatable.component.html',
})
export class DatatableComponent {
displayedColumns = ['id', 'collectionName', 'displayType', 'size'];
datatableDatabase: SearchDataSet | null;
dataSource: SearchDataSource | null;
constructor(
private searchService: SearchService
) {
this.datatableDatabase = new SearchDataSet(searchService);
this.dataSource = new SearchDataSource(this.datatableDatabase);
}
}
export class SearchDataSet {
dataChange: BehaviorSubject<Asset[]> = new BehaviorSubject<Asset[]>([]);
get data(): object { return this.dataChange.value; }
constructor(
private searchService: SearchService
) { }
getCollections(): Observable<Asset[]> {
return this.searchService.getInitialCollections()
.map(this.searchService.readCollectionResult);
}
}
export class SearchDataSource extends DataSource<Asset> {
constructor(
private _searchDataset: SearchDataSet
) {
super();
}
/** Connect function called by the table to retrieve one stream containing the data to render. */
connect(): Observable<Asset[]> {
return this._searchDataset.dataChange
.switchMap(() => this._searchDataset.getCollections());
}
disconnect() { }
}
search.service.ts
@Injectable()
export class SearchService {
constructor(
private apiService: ApiService
) { }
private searchSource = new BehaviorSubject<object>(this.getInitialCollections());
public currentMessage = this.searchSource.asObservable();
getInitialCollections() {
return this.apiService.post('/path/to/your/endpoint/_search');
}
search(phrase: string) {
let results = this.apiService.post('/path/to/your/endpoint/_search', { phrase: phrase })
.subscribe(data => this.changeMessage(data));
}
changeMessage(results: object) {
this.searchSource.next(results)
}
readCollectionResult(result: any): Asset[] {
return result.data.map(asset => {
return {
id: asset.id,
collectionName: asset.collectionName,
collectionId: asset.collectionId,
objectType: asset.objectType,
displayType: asset.displayType,
size: asset.size,
createDate: asset.createDate,
modifiedDate: asset.modifiedDate,
publishedDate: asset.publishedDate,
parentFolderId: asset.parentFolderId
};
});
}
}
Working on this now at #8162 - please feel free to add comments to help contribute
@iamwhitebox: I spent a few days to get this working too. For my service, I used the following approach to make clients aware of updates:
https://angular.io/guide/component-interaction#parent-and-children-communicate-via-a-service
Inside that service, I used HttpClient to get my data, and store it in an array. RxJS Subjects in the service announce when data is available.
I used the following example for the table setup:
https://stackblitz.com/edit/angular-material2-table?file=app%2Fapp.component.ts
I set up the constructor in that component to have a listener that will respond to data updates, in my case a search (see parent-and-children from angular.io above).
On that notification back in my component, when data is received, I set the passed in array of data to a local instance (which is used to replace the NAMES and COLORS variables from the stackblitz example).
Also in my table component, I added a new method that is called as part of the data subscription, that re-initializes the DataSource when data is received (this.dataSource = new ExampleDataSource()). It works, but there is probably a better way to repopulate the DataSource. A lot of trial and error was involved :)
I had lot of troubles trying to use this approach:
import { DataSource } from '@angular/cdk/collections';
....
I could get the table, but to sort the columns was impossible because sort wasn't a known property of Datasource, etc, etc
finally i noted that was using "@angular/material": "^5.0.0-rc0",
Currently I'm working with MatTableDataSource
IMPORTS
import {MatTableDataSource} from '@angular/material';
CLASS VARIABLES
private ELEMENT_DATA: reportInterface[] = [];
public tbDataSource;
public displayedColumns;
and in the constructor
this.dataService.getReport().subscribe(results => {
if(!results)return;
this.ELEMENT_DATA = results;
this.displayedColumns = [.............];
this.tbDataSource = new MatTableDataSource(this.ELEMENT_DATA);
this.tbDataSource.sort = this.sort;
});
and here is my filter function
applyFilter(filterValue: string) {
this.tbDataSource.filter = filterValue;
}
I think this is faster and easier
It would have helped me a lot to give the transition steps from a REST data source populating a plain HTML table to a mat-data. Like whitebox (above), i've spent a few hours on this already and haven't found joy
Another PR to improve docs as well as open up the table data source API to allow just normal data arrays and streams that emit arrays. If changes to your data occurs, you have the option to call renderRows
rather than changing your data array reference.
Agreed, I think allowing normal arrays to be the datasource would simplify
things for a lot of users.
On Tue, Jan 23, 2018 at 6:51 PM, Andrew Seguin notifications@github.com
wrote:
Another PR to improve docs as well as open up the table data source API to
allow just normal data arrays and streams that emit arrays. If changes to
your data occurs, you have the option to call renderRows rather than
changing your data array reference.9489 https://github.com/angular/material2/pull/9489
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/angular/material2/issues/8227#issuecomment-359972014,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AFrq6iOp7Tpxw7zGQ9xoFIYTgPfh17pdks5tNnCbgaJpZM4QRwuL
.
This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.
Read more about our automatic conversation locking policy.
_This action has been performed automatically by a bot._
Most helpful comment
I had lot of troubles trying to use this approach:
import { DataSource } from '@angular/cdk/collections';
....
I could get the table, but to sort the columns was impossible because sort wasn't a known property of Datasource, etc, etc
finally i noted that was using "@angular/material": "^5.0.0-rc0",
Currently I'm working with MatTableDataSource
IMPORTS
import {MatTableDataSource} from '@angular/material';
CLASS VARIABLES
private ELEMENT_DATA: reportInterface[] = [];
public tbDataSource;
public displayedColumns;
and in the constructor
this.dataService.getReport().subscribe(results => {
if(!results)return;
this.ELEMENT_DATA = results;
this.displayedColumns = [.............];
this.tbDataSource = new MatTableDataSource(this.ELEMENT_DATA);
this.tbDataSource.sort = this.sort;
});
and here is my filter function
applyFilter(filterValue: string) {
this.tbDataSource.filter = filterValue;
}
I think this is faster and easier