I am trying to update the view of an Angular Component when data changes. I was going through the ChangeDetectionStrategy.OnPush and thought this might solve my problem. However, I didn't succeed.
I have a upcoming-studies component and this is a child component of studies component.
upcoming-studies.component.html
<div>
<ngx-datatable
#upcoming
class="material"
[headerHeight]="50"
[footerHeight]="50"
[rowHeight]="'auto'"
[rows]="rows"
[columns]="columns"
[columnMode]="'flex'"
[selected]="selected"
[selectCheck]="selectUnselect"
[selectionType]="'single'"
[limit]="10"
(select)='onSelect($event)'>
</ngx-datatable>
</div>
The [rows]="rows", here variable rows gets data from backend using HTTP call.
I am trying to update the view, whenever this variable rows gets updated or whenever HTTP call is made. Here is part of my ts file.
upcoming-studies.component.ts
@Component({
selector: 'rmis-upcomingstudies',
templateUrl: './upcoming-studies.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
styleUrls: ['./upcoming-studies.component.css']
})
export class UpcomingStudiesComponent implements OnInit, OnChanges {
// ToDo: Check specific data types
@Input() rows = [];
@Input() temp = [];
constructor(private studiesService: StudiesService,
private exceptionService: ExceptionService,
private cd: ChangeDetectorRef) {
// Set up the column labels and properties for the upcoming study table
this.columns = [
{prop: 'protocol_number', name: 'Protocol Number', flexGrow: 1},
{prop: 'start_date', name: 'Start Date', flexGrow: 1},
{prop: 'end_date', name: 'End Date', flexGrow: 1},
{prop: 'patient_count', name: 'Patient Count', flexGrow: 1},
{prop: 'trial_country', name: 'Country', flexGrow: 1},
];
}
ngOnInit() {
this.getUpcomingStudies();
}
ngOnChanges() {
//Trying to print the `rows` and `temp` to see if changes in these variable are detected. so that I can run cd.detectChangese() method to update the view.
}
First time the HTTP call happens onInIt(), the next time I am calling getUpcomingStudies() of upcoming-studies-component.ts from a differnet Component (Neither Parent not Child) and that is when I need to update the view. The HTTP call is made and updated data is also returned that updates temp and rows variable but the number of rows on UI does not change. Basically, it reduces the number of rows from upcoming studies view, so I need to update that view so it shows 1 less row. As you can see, I have tried using ChangeDetectionStrategy, but I am not sure on how to make this thing work. Any input would be appreciated. Thanks!
Update 1: I think, my @Input() variables are not getting updated and thus no change detection, as I tried printing them in ngOnChanges, but ngOnChanges never got executed. Is there any other way to perform the same action?
Update 2:
I have made some changes in the ways rows and temp are updated. As I had mentioned earlier, upcoming-studies component is a child of studies component. I am passing rows and temp from studies to upcoming-studies component as shown below:
studies.component.html
<upcoming-studies [rows] = rows [temp] = temp>
</upcoming-studies>
The studies component makes an HTTP call to get the data(rows and temp).
studies.component.ts
public rows = [];
public temp = [];
ngOnInit() {
this.getUpcomingStudies();
}
getUpcomingStudies() {
this.studiesService
.getUpComingStudies()
.subscribe(
// the first argument is a function which runs on success
(data) => {
console.log('Data from backend-upcoming', data);
this.temp = data['records'];
// this.temp = JSON.parse(JSON.stringify(this.temp));
this.rows = this.studiesService.util_to_cal_time(data['records']);
// this.rows = JSON.parse(JSON.stringify(this.rows));
// this.rows = data.records;
},
// the second argument is a function which runs on error
(err: HttpErrorResponse) => {
this.exceptionService.errorResponse(err);
},
// the third argument is a function which runs on completion
() => {
}
);
}
For first time, ngOnInit in studies component, calls the getUpcomingStudies method. After this, it's called from another component. Let me know If you need more details.
util_to_cal_time - It just modify the time and return the same array.
util_to_cal_time(studies: Array<any>) {
for (const each of studies) {
const sDate = new Date(each.start_date * 1000);
each.start_date = sDate.getUTCMonth() + 1 + '/' + sDate.getUTCDate() + '/' + sDate.getFullYear();
const eDate = new Date(each.end_date * 1000);
each.end_date = eDate.getUTCMonth() + 1 + '/' + eDate.getUTCDate() + '/' + eDate.getFullYear();
}
console.log(studies);
return studies;
}
rowsproperty a completely new reference (clone the array) each time it is updated. For examplethis.rows = JSON.parse(JSON.stringify(this.rows))or if your using Lodash:this.rows = _.cloneDeep(this.rows). If that works -- that will at least confirm your issue.ngOnChangesdetects change inrowsandtempvariables only first time.. Then any other change in these arrays is not being detected as pointed out by @Graztok. And hence I am not able to run ChangeDetection. Do you have any input on this?rows, show some code