Regarding material table in angular 2 . In my ngonit() I have this.mydatasource.sort = this.sort. The sorting works but while the data is loading I briefly see the table header (flicker) and then whole table appears. As soon as I do a table ngif="mytabledata" the header flicker goes away and the whole table with data appears at once like I want but now the sort does not work since when it hits ngonit my data is not loaded. (data is loaded on ngonchanges that is fired when input param changes). How can I fix this conundrum ?
-
Please read [How to ask](https://stackoverflow.com/help/how-to-ask) to improve your question. – Batajus Dec 12 '18 at 20:25
-
please try to recreate your scenario may be on stackblitz: https://stackblitz.com/angular/ymoobndeelb so that people can look and help out further – Rikin Dec 12 '18 at 20:44
-
Sorry I am having hard time to recreate the issue in a sample. Sample works fine. Will delete this question if I am not able to post sample. – Gullu Dec 12 '18 at 21:21
-
@Rikin, finally able to reproduce. Here you go. https://stackblitz.com/edit/angular-table-sort-not-working – Gullu Dec 12 '18 at 21:27
-
@Gullu here's working example: https://stackblitz.com/angular/drqkekyagre – Rikin Dec 12 '18 at 21:48
-
@Rikin, please read my question. I have to load data on ngonchanges(). When you have an input param to any component and when that param changes..onchanges is fired. – Gullu Dec 12 '18 at 21:51
1 Answers
Please Note: You have to wrap this.dataSource.sort = this.sort
in a setTimeout()
to establish the link on the digest cycle, without it, the @ViewChild(MatSort) sort: MatSort
is undefined due to the *ngIf
.
ngOnChanges() {
const ELEMENT_DATA1: PeriodicElement[] = [
{ position: 1, name: 'Hydrogen', weight: 1.0079, symbol: 'H' },
{ position: 2, name: 'Helium', weight: 4.0026, symbol: 'He' },
{ position: 3, name: 'Lithium', weight: 6.941, symbol: 'Li' },
{ position: 4, name: 'Beryllium', weight: 9.0122, symbol: 'Be' },
{ position: 5, name: 'Boron', weight: 10.811, symbol: 'B' },
{ position: 6, name: 'Carbon', weight: 12.0107, symbol: 'C' },
{ position: 7, name: 'Nitrogen', weight: 14.0067, symbol: 'N' },
{ position: 8, name: 'Oxygen', weight: 15.9994, symbol: 'O' },
{ position: 9, name: 'Fluorine', weight: 18.9984, symbol: 'F' },
{ position: 10, name: 'Neon', weight: 20.1797, symbol: 'Ne' },
];
this.dataSource.data = ELEMENT_DATA1;
console.log(this.sort) //undefined
setTimeout(() => {
console.log(this.sort) //not undefined
this.dataSource.sort = this.sort;
})
}
Stackblitz
Digest Cycle is a term defined in the AngularJS days... see this SO answer for more information.... Believe it is now more commonly referred to as Change Detection
Angular defines a concept of a so called digest cycle. This cycle can be considered as a loop, during which Angular checks if there are any changes to all the variables watched by all the $scopes. So if you have $scope.myVar defined in your controller and this variable was marked for being watched, then you are explicitly telling Angular to monitor the changes on myVar in each iteration of the loop.
Angular - what triggers the digest cycle for 2 way data bindings?
See this non Angular specific answer for why setTmiout()
works.
A browser has to do a number of things pretty much all at once, and just one of those is execute JavaScript. But one of the things JavaScript is very often used for is to ask the browser to build a display element. This is often assumed to be done synchronously (particularly as JavaScript is not executed in parallel) but there is no guarantee this is the case and JavaScript does not have a well-defined mechanism for waiting.
The solution is to "pause" the JavaScript execution to let the rendering threads catch up. And this is the effect that setTimeout() with a timeout of 0 does. It is like a thread/process yield in C. Although it seems to say "run this immediately" it actually gives the browser a chance to finish doing some non-JavaScript things that have been waiting to finish before attending to this new piece of JavaScript.
Why is setTimeout(fn, 0) sometimes useful?
In Summary
Digest Cycle/Change Detection commonly refers to the non-Angular browser related task such as rendering a view item etc... in this example, your ngOnchange()
was not waiting for the rendering threads, created by your *ngIf
becoming true, to complete in the browser... and was trying to bind the @ViewChild
view reference before it was actually there on the DOM...
- Reason one console.log was undefined
- And the other inside of the
setTimeout()
was not
Wrapping that line of code in the setTimeout()
made it wait for the browser to finish its rendering task created by your *ngIf
.

- 10,499
- 2
- 34
- 53
-
OP's question is that empty header displays and if OP applies `*ngIf="dataSource.data"` sorting breaks. – Rikin Dec 12 '18 at 22:02
-
-
@Marshal, works exactly like i want and answers question. But what the heck is "setTimeout() to establish the link on the digest cycle". Is there any link online to read up on this. What should I google for ? Thanks – Gullu Dec 12 '18 at 22:19
-