Reputation: 630
I'm trying to create some expansion panels with mat-table's inside, my problem is i have to resize my windows before my view will change. My data is loading fine and all but somehow my view does not update. My view where my expansion panels should be, is just all blank. Untill i click a button or resize my window. What can cause something like this?
In my ngOnInit() i call
this.getSale1();
.HTML:
<mat-accordion>
<mat-expansion-panel *ngFor="let data of mySaleModelArray2 ">
<mat-expansion-panel-header>
<mat-panel-title>
<h6 class="salepanelheadtext">Bar:</h6>{{data.name}}
</mat-panel-title>
<mat-panel-description>
<h6 class="salepanelheadtext2">Total:</h6> {{data.total_sales}}
</mat-panel-description>
</mat-expansion-panel-header>
<div class="example-container mat-elevation-z8">
<mat-table #table [dataSource]="data.sales" >
<!-- PLU Column -->
<ng-container matColumnDef="pluNo">
<mat-header-cell *matHeaderCellDef >
#
</mat-header-cell>
<mat-cell *matCellDef="let salesdata">
{{salesdata.beerline}}
</mat-cell>
</ng-container>
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
<mat-cell *matCellDef="let salesdata">
{{salesdata.pluName}}
</mat-cell>
</ng-container>
<!-- Sold_Count Column -->
<ng-container matColumnDef="sold_count">
<mat-header-cell *matHeaderCellDef>
QTY
</mat-header-cell>
<mat-cell *matCellDef="let salesdata">
{{salesdata.sold_count}}
</mat-cell>
</ng-container>
<!-- PLU Price Column -->
<ng-container matColumnDef="pluPrice">
<mat-header-cell *matHeaderCellDef> Price </mat-header-cell>
<mat-cell *matCellDef="let salesdata">
{{salesdata.pluPrice}}
</mat-cell>
</ng-container>
<!---->
<ng-container matColumnDef="total_amount">
<mat-header-cell *matHeaderCellDef>
Total
</mat-header-cell>
<mat-cell *matCellDef="let salesdata">
{{salesdata.pluPrice * salesdata.sold_count}}
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns2"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns2;"></mat-row>
</mat-table>
</div>
</mat-expansion-panel>
</mat-accordion>
.TS:
//Get data from Sale1List
getSale1() {
this.customersService.getSale1()
.subscribe(
dataList => {
this.updateDataTable(dataList);
}
)
}
updateDataTable(dataList) {
for(var i = 0;i < dataList.length; i++){
var saleData = <SaleDataModel>dataList[i];
var mySaleModelTest = this.mySaleModelArray2.find(x => x.name == dataList[i].name);
if(mySaleModelTest == null){
//first time creating the object with the bar name
var tempArray = Array();
tempArray.push(saleData);
this.mySaleModelArray2.push(new Sale1Model(dataList[i].name,dataList[i].pluPrice * dataList[i].sold_count,tempArray));
}else{
//changing the object with the bar name because it already exist
mySaleModelTest.total_sales = mySaleModelTest.total_sales + dataList[i].pluPrice * dataList[i].sold_count;
mySaleModelTest.sales.push(saleData);
}
}
}
Upvotes: 6
Views: 20122
Reputation: 3443
ChangeDetectorRef
will do the trick.
Inject him in the constructor.
constructor(
...
private cdr: ChangeDetectorRef,
...
) { }
edit getSale1
like this in order to use the cdr:
getSale1() {
this.customersService.getSale1()
.subscribe(
dataList => {
this.updateDataTable(dataList);
this.cdr.detectChanges();
}
)
}
But why I have to use the ChangeDetectorRef?
Angular, by default, use the ChangeDetectionStrategy.default
that use its logic to "wake-up" the component for the render. More spec here: https://angular.io/api/core/ChangeDetectionStrategy
There are certain cases where this isn't enough. One case could be a very big nested *ngFor
.
So why use the cdr?
As I said, there are some cases when Angular does not wake up its renderer. Since every situation is not the same, it's quite impossibile to define an absolute answer to this. What cdr.detectChanges()
does, is to allow the method to inform the Angular's rendered to force the render of its component.html. In this way, no matter which strategy
are you using (even if it's .onPush
) the component will be re-rendered.
But be careful. you have to think what you are doing before implementing this. For example, re-render the html fire the ngOnChanges
event. So you could enter an endless loop.
More info about cdr: https://angular.io/api/core/ChangeDetectorRef
Hope that this cleared out some doubts.
Upvotes: 11
Reputation:
Use a custom trackby function with a unique return statement (for instance, IDs are supposed to be unique, or you can track on the property you change)
*ngFor="let data of mySaleModelArray2; trackBy: customTB"
customTB(item, index) {
return `${item.id}-${index}`;
}
Upvotes: 4
Reputation: 29795
If you are simply pushing object
or data into an array, angular
wont detect it as changed property (which is bad). Because you did not completely re-assign to it.
What you could do is :
mySaleModelArray2
using temp array (not a good solution though).Upvotes: 0