I have JSON response for sport events in following format.
[
{
"game_id": 1,
"team1": "Manchester United",
"team2": "Chelsea",
"sport_id": 1,
"score": "1:1",
"bets": [
{
"bet": "1",
"coefficient": 1.2
},
{
"bet": "2",
"coefficient": 2.4
},
{
"bet":"X",
"coefficient": 3.0
}
]
},
{
"game_id": 2,
"team1": "Liverpool",
"team2": "Real Madrid",
"sport_id": 1,
"score": "0:1",
"bets": [
{
"bet": "1",
"coefficient": 1.2
},
{
"bet": "2",
"coefficient": 5.0
},
{
"bet":"X",
"coefficient": 3.5
}
]
}
]
... and so on ...
What I want to accomplish ?
-Every 5 seconds, I'm requesting new(fresh/updated) data from server. Normally, coefficients for the games are changed. When the new coefficient for particular game, is larger than the old one, I want element displaying the coefficient, to change background-color to green, when is smaller to change background-color to red, and no changes otherwise.
What have I tried/realized ?
-I realized that, to detect property changes of input object in component, I need to use ngDoCheck() lifecycle method.
-After every API response, I was creating new array instance, and consequently, *ngFor was rerendering the page and reinitializing child components with the new array data, so - no way to keep old values in app-match-row-component level.
-After that I made some changes in code, after every API response, do not create new array of objects, only update objects where changes are present, so the array stays the same, only object property values are changed.
-Then I faced new problem. *ngFor was not rerendering the DOM, unless there is insertion/deletion of elements in the array. To fix that I set trackBy function as a property of *ngFor. After that, I can see the changes, but still, I can not keep the old values of coefficients, looks like, child components are still reinitializing where changes are present.
Here is table-component.html:
<table class="w-100 text-white">
<thead class="image-background">
<th>ID</th>
<th>HOME</th>
<th>AWAY</th>
<th>SCORE</th>
<th>BETS</th>
</thead>
<tbody>
<tr *ngFor="let match of data; let index=index;trackBy:trackFn" app-match-row [match]="match"
[ngClass]="{'even':index%2==0,'odd':index%2!=0}"></tr>
</tbody>
Here is table-component.ts(Although, it is not important, only updates to the array of events):
import { Component, DoCheck, NgZone, OnInit } from '@angular/core';
import { DataService } from 'src/app/services/data.service';
import { LiveEvent } from 'src/app/data classes/LiveEvent';
import { ChangeDetectorRef } from '@angular/core';
@Component({
selector: 'app-table',
templateUrl: './table.component.html',
styleUrls: ['./table.component.css']
})
export class TableComponent implements OnInit {
data: LiveEvent[] = [];
error: string;
constructor(private dataService: DataService, private zone: NgZone) { }
trackFn(index:number, item:LiveEvent){
return item.live_game_LIST;
}
ngOnInit(): void {
setInterval(() => {
this.dataService.refreshData().subscribe((response: any) => {
this.data.forEach((member: LiveEvent, index: number, array: LiveEvent[]) => {
var exists: boolean = false;
try {
response.forEach((element: any, index: number, array: any[]) => {
if (member.broj == element.broj) {
member.deserialize(element);
exists = true;
array.splice(index, 1);
throw new Error();
}
})
}
catch (e) { }
finally {
if (!exists)
array.splice(index, 1);
}
})
response.forEach((element: any) => {
this.data.push(new LiveEvent().deserialize(element));
})
},
(error) => {
this.error = error.statusText;
})
}, 5000)
}
}
And regardless of app-match-row.html content, here is app-match-row.ts:
import { AfterContentInit, AfterViewInit, ChangeDetectionStrategy, Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';
import { LiveEvent } from 'src/app/data classes/LiveEvent';
@Component({
selector: '[app-match-row]',
templateUrl: './match-row.component.html',
styleUrls: ['./match-row.component.css']
})
export class AppMatchRowComponent implements OnInit {
@Input() match: LiveEvent
k1: string | number;
k2: string | number;
k1_old: string | number;
k2_old: string | number;
k1_increase: boolean = false;
k2_increase: boolean = false;
k1_decrease: boolean = false;
k2_decrease: boolean = false;
areK1FlagsFalse():boolean{
return !this.k1_increase && !this.k1_decrease;
}
areK2FlagsFalse():boolean{
return !this.k2_increase && !this.k2_decrease;
}
constructor() { }
ngOnInit(): void {
this.k1 = this.match.bets[0];
this.k2 = this.match.bets[2];
}
ngDoCheck(): void {
if(this.k1 > this.k1_old){
console.log("OLD: " + this.k1_old + "; NEW: " + this.k1);
this.k1_increase = true;
this.k1_old = this.k1;
}else if(this.k1 < this.k1_old){
console.log("OLD: " + this.k1_old + "; NEW: " + this.k1);
this.k1_decrease = true;
this.k1_old = this.k1;
}else{
this.k1_increase = false;
this.k1_decrease = false;
}
if(this.k2 > this.k2_old){
console.log("OLD: " + this.k1_old + "; NEW: " + this.k1);
this.k2_increase = true;
this.k2_old = this.k2;
}else if(this.k2 < this.k2_old){
console.log("OLD: " + this.k1_old + "; NEW: " + this.k1);
this.k2_decrease = true;
this.k2_old = this.k2;
}else{
this.k2_increase = false;
this.k2_decrease = false;
}
}
}
Every log in the console, the old and the new values are the same, I can't catch the moment when they're different to apply style.
I also want to note that, this is simplified version of my code, just to point-out my logic. There may be a few mistakes.
Feel free to ask me questions, If I was not clear enough.
Thank you very much in advance. :D