#MatTable: setting dataSource in ngOnChanges does not work

8 messages ยท Page 1 of 1 (latest)

severe skiff
#

I am implementing a datatable using MatTable form Angular Material. RIght now I am trying to refactor the component so that the user can pass an array of objects as a data source and I convert it to a MatTableDataSource as soon as possible (ideally before template is bound to Input()s values) in ngOnChanges which, to my understanding, is the first lifecycle hook that gets called (if there inputs, otherwise it is ngOnInit). The problem is that no row is actually rendered by doing. You can find a complete minimal reproduction here:
https://stackblitz-starters-cgsrin.stackblitz.io
My guess is that I did not understand well how binding works in the lifecycle of a component.

#

I have also written a simple test using HarnessLoader which fails because of, at least I think, something wrong in the ngOnChanges method. I don't know if Stackblitz can run tests but it is there in table.component.spec.ts.

cobalt bronze
#

Hey there ๐Ÿ‘‹๐Ÿป

There were a few issues here. I prefer to use input setters instead of onValueChanges, it's much simpler ๐Ÿ˜ƒ

Here is a fork of you project:

https://stackblitz.com/edit/stackblitz-starters-adxqtq?file=src%2Ftable%2Ftable.component.html

In the template, on line 7, we need to use element[column] instead of element.column, since column is dynamic and not a known property name.

Let me know if you have any questions!

An angular-cli project based on @angular/animations, @angular/common, @angular/compiler, @angular/core, @angular/forms, @angular/platform-browser, @angular/platform-browser-dynamic, @angular/router, core-js, rxjs, tslib and zone.js

#

Also, the dataSource in your template needs to point to the config.data that you're passing in for the table to know what the data is.

severe skiff
#

The issue is not how to make the table work but how to convert config.data from object[] to MatTableDataSource before config.data is assigned to [dataSource]. The reason why I want to do this is that I don't want to expose internal implementations of the component: if I typed config.data directly as MatTableDataSource the parent component would have to import it and that's a violation of the encapsulation principle.

cobalt bronze
#

Couldn't you just handle that within the input setter on the child component? The implementation would still be encapsulated, the parent component still uses object[]

marble pollen
#

I am not sure to understand, but from what I get, you have a component with an @Input array and you want to convert it to MatTableDataSource.
if this is the case, you should use a setter as Chris Perko said:

dataSource: MatTableDataSource; 
private _config: EgTableConfig;

// only in case you need config elsewhere, otherwise you don't need this getter nor the private _config
get config(): EgTableConfig {
    return this._config;
}
@Input() set config(config: EgTableConfig) {
    this.dataSource = new MatTableDataSource(config.data);
    this._config = config;
}
severe skiff
#

Thank you very much, it now passes the test. I did not know about using setter and getters for @Input(). Also, is prefixing variables with _ a convention iIdid not know about?