components: Docs bug: How to add rows to table
Bug, feature request, or proposal:
We really need a straightforward example of how to dynamically add a row to a table, I see some other issues in the issue tracker on this, but am still having trouble finding info on it, so I am getting frustrated tbh
What is the expected behavior?
Expected to find docs for dynamically adding a row
What is the current behavior?
Do not find docs to dynamically add a row
What are the steps to reproduce?
Look at docs until giving up
I didn’t post this SO question, but there are several like it: https://stackoverflow.com/questions/47581267/how-to-add-data-dynamically-to-mat-table-datasource
I assume the answer is something like this:
export class MyDataSource extends DataSource<any> {
// implement connect, etc
}
const ds = new MyDataSource();
// ...later on, we want to add some rows
ds.whatDoWeCallToAddSomeRowsPlease(); // ???
Adding rows dynamically should be one of the first examples in the docs, I would hope, please advise
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 4
- Comments: 31 (23 by maintainers)
MatTableDataSource
does not have therenderRows
method. It’s inCdkTable
|MatTable
.However, in Angular 5.2.0 it still doesn’t work for me. I don’t even see new rows (@ORESoftware at least sees empty rows).
It only works when I do:
which I find not very elegant.
@ORESoftware I’m sure @andrewseguin would be able to explain more effectively, but I’ll try:
DataSource
When using
MatTable
orCdkTable
, you must provide it with a data source. Any data source implementation that you provide needs aconnect()
anddisconnect()
method. The former is used by the table as a consistent interface to get a stream of data to display.The connect method should return an
Observable<MyRowType[]>
. There is an agreement between the data source and the view that the table only needs to perform change detection when the Observable emits, and not any more. If that agreement did not exist, the table would have to perform change detection on each every cycle, which would be highly unnecessary in most use cases.MatTableDataSource
As I’m sure you’re aware, this is a convenience implementation of a
DataSource
. You provide an array of rows (viadata
) and it provides a very simple interface for setting up filtering/pagination/etc on those rows.Any time you want to change the data that the data source is sending to the table, you simply overwrite the
data
property, and that array will propagate through any established filters, pagination, or sorting and be sent to the MatTable.But why not just allow
push
andunshift
?Those operations mutate the array. Neither the data source nor the table can be aware of the changes you’ve made to your array by using those operations without liberal use of change detection.
I still really want
addRow
andremoveRow
methodsMaybe try extending
MatTableDataSource
?@oomz it’s like so
new MatTableDataSource().renderRows()
you normally wouldn’t use it like that, but you get the idea. note that this method is only available in 5.2.0+
@ORESoftware
Same issues some other users are having here. The table only updates if you change the whole array, concat and push DO NOT work.
My ‘solution’:
this.dataSource = this.dataSource.concat(someNewData)
Any solution for this? I’m having the same problem when I try to edit a row with the data that comes to me through a socket.
I’m using
angular material 5.2.5
The renderRows() method does not seem to work here
UPDATE:
After much searching I could solve it with this example in stackblitz
Also add
ChangeDetectorRef
this works for me@andrewseguin @willshowell
one thing that still perplexes me, given Will’s example above:
do you really want users overwriting the entire array?
this.dataSource.data = messages
it doesn’t make a lot of sense to overwrite the whole array. not only that, but to be required to overwrite the entire array to get re-rendering? It makes no sense to me. I don’t see how the library will save on rendering time if it has to compare all the elements of the old array with the new one to see where changes are, etc.
@ORESoftware thanks for the video.
FWIW, if you’re only ever adding rows from the data service, perhaps try something like this:
Obviously I don’t know how your data service works or really any of the rest of the app, but maybe it will show how easy it can be to add rows.
This way could be even simpler:
What you’re experiencing with empty rows not showing data until you navigate tabs is almost certainly a symptom of change detection not being run when you expect. You could validate this by adding a click handler to one of your cell templates. When you click it, change detection should run and the rows should update.
You talk about performance costs around 3:30. As far as I’m aware, this whole system was designed to be as performant as possible, thus leaving it up to the user to define when change detection should occur. Creating a new array via
concat
or spread assignment doesn’t do a deep copy, AFAIK it simply updates the object reference, so I think the costs you’re expecting by assigning a new array are much much lower than anticipated.In any case, writing your own data source is pretty easy and you can make it as flexible and customizable as you need. The only condition is that your
connect()
method emits each time you want to render an update.Finally, consider what
addRow()
andremoveRow()
open up… Why include those but notaddRows()
,removeRows()
,swapRows()
,invertTable()
,replaceRow()
? They’re all valid needs, but supporting them all would be overkill when it’s so easy to accomplish otherwise.Thanks, I don’t think that’s a great solution (overwriting the original array), I made a video demonstrating the problem
https://www.useloom.com/share/83b4388cf48f49178280bec3d3bbc984