dukaric1991
dukaric1991

Reputation: 1430

Calling the service function with button click doesnt update view

When i call this.getLeaderboard(); in ngOnInit() in leaderboard.component.ts the leaderboard is shown only on page start or page refresh which is normal. But i also want to fetch and show leaderboard on button click from app.component.ts.

When i click on button the flow goes to leaderboard.component which calls the leaderboard.service but nothing is shown or updated in leaderboard.component.html. If i console.log the values are there but the DOM is not updated...

What am i missing here?

app.component.html

  <div class="col nopadding">
         <button id="bottomButton2" type="button" class="btn btn-bottom" (click)="getLeaderboard()">
             <img id="bottom2" class="navbar-bottom-pics" src="assets\img\podium.svg">
              <img id="bottom22" class="navbar-bottom-pics hide" src="assets\img\podiumSelected.svg">
         </button>
    </div>

app.component.ts

 import { Component, Injectable } from '@angular/core';
    import { MatchesComponent } from './matches/matches.component';
    import { LeaderboardComponent } from './leaderboard/leaderboard.component';
    import { ClubStatisticsComponent } from './club-statistics/club-statistics.component';

    @Component({
     selector: 'app-root',
     templateUrl: './app.component.html',
     styleUrls: ['./app.component.css'],
     providers: [LeaderboardComponent,MatchesComponent,ClubStatisticsComponent]
     })

    export class AppComponent{

    constructor(private match_component:MatchesComponent, private 
    leaderboard_component:LeaderboardComponent, private 
    clubstatistics_component:ClubStatisticsComponent){}

    //CALLS FOR BOTTOM NAVBAR
    getLeaderboard(){
      //POSITION SCREEN TO TOP
      window.scrollTo(0, 0);
      //CALL GET LEADERBOARD
      this.leaderboard_component.getLeaderboard();
    }

leaderboard.component.ts

import { Component, OnInit, Injectable} from '@angular/core';
import { leaderboardInstance } from './leaderboardInstance';
import { LeaderboardService } from './leaderboard.service';

@Component({
  selector: 'app-leaderboard',
  templateUrl: './leaderboard.component.html',
  styleUrls: ['./leaderboard.component.css'],
  providers: [LeaderboardService]
})

@Injectable()
export class LeaderboardComponent implements OnInit {

  public leaderboard: leaderboardInstance[];
  public finalLeaderboard: leaderboardInstance[] = new Array();

  constructor(private leaderboard_service: LeaderboardService) { }

  ngOnInit() {

      this.getLeaderboard();

  }

  //GET ACTUAL SERVER JSON RESPONSE AND SUBSCRIBE IT TO array
  getLeaderboard(){
    console.log("leaderboardComponent");
    this.leaderboard_service.getLeaderboard().subscribe(leaderboard =>{ this.leaderboard = this.formatMatchesSingles(leaderboard)});

  }

  formatMatchesSingles(leaderboard){
    console.log("formatMatches");
    let uniqueNames = [];
    let uniqueSurnames = [];
    let matchesPlayed = [];
    let matchesWon = [];

    for(let i = 0; i< leaderboard.length; i++){   

      //FIND ALL UNIQUE NAMES 
      if(uniqueNames.indexOf(leaderboard[i].name1) === -1){
          uniqueNames.push(leaderboard[i].name1);        
      }
      if(uniqueNames.indexOf(leaderboard[i].name2) === -1){
        uniqueNames.push(leaderboard[i].name2);        
      }

      //FIND ALL UNIQUE SURNAMES
      if(uniqueSurnames.indexOf(leaderboard[i].surname1) === -1){
        uniqueSurnames.push(leaderboard[i].surname1);        
      }
      if(uniqueSurnames.indexOf(leaderboard[i].surname2) === -1){
        uniqueSurnames.push(leaderboard[i].surname2);        
      }

    }

    //CALCULATE MATCHES PLAYED
    for(let i=0;i<uniqueNames.length;i++){

      let played = leaderboard.reduce(function(s, o) {
      if (o.name1 === uniqueNames[i] && o.doubles == "0") s++;
      if (o.name2 === uniqueNames[i] && o.doubles == "0") s++;
      return s;
    }, 0);
    matchesPlayed[i]=played;
    }

    //CALCULATE WINS
        for(let i=0;i<uniqueNames.length;i++){

      let wins = leaderboard.reduce(function(s, o) {
      if (o.name1 === uniqueNames[i] && o.sets_team1 > o.sets_team2 && o.doubles == "0") s++;
      else if(o.name2 === uniqueNames[i] && o.sets_team2 > o.sets_team1 && o.doubles == "0") s++;
            return s;
        }, 0);
        matchesWon[i]=wins;
    }

    //CREATE USER OBJECT, ASSIGN ALL VARIABLES AND ADD IT TO ARRAY
    for (let i = 0; i < uniqueNames.length; i++) { 

      let MatchesNo: number = parseFloat(matchesPlayed[i]);
      let MatchesWonNo: number = parseFloat(matchesWon[i]);
      let MatchesLostNo: number = MatchesNo - MatchesWonNo;  //CALCULATE LOSES
      let WinPercentage: number;

      if (MatchesNo > 0 && MatchesWonNo == 0) WinPercentage = 0;
      else WinPercentage = (MatchesWonNo/MatchesNo)*100; //CALCULATE PERCENTAGE
      let newInstance = new leaderboardInstance();
      newInstance.name = uniqueNames[i];
      newInstance.surname = uniqueSurnames[i]
      newInstance.played = matchesPlayed[i];
      newInstance.wins = matchesWon[i];
      newInstance.loses = MatchesLostNo;
      newInstance.percentage = Math.floor(WinPercentage);
      this.finalLeaderboard.push(newInstance);

    }

    //SORT
    this.finalLeaderboard.sort(function(a, b){

      if(a.wins === b.wins){

        if(a.percentage != b.percentage){ //SORT BY PERCENTAGE
          let x = a.percentage, y = b.percentage;  
          return y < x ? -1 : y > x ? 1 : 0;
        }
        else{ //IF ALSO PERCENTAGES ARE THE SAME THEN SORT BY PLAYED MATCHES
          let x = a.played, y = b.played;
          return y < x ? -1 : y > x ? 1 : 0;
        }
      }
      return b.wins - a.wins //DEFAULT SORT BY WINS
    });


    return this.finalLeaderboard;
  }

}

leaderboard.service.ts

import { Injectable } from '@angular/core';
import { leaderboardInstance } from './leaderboardInstance';
import { Observable, Subject } from 'rxjs';
import { HttpClient, HttpParams } from '@angular/common/http';
import {SHA256} from 'crypto-js';

@Injectable()
export class LeaderboardService {

constructor(private http: HttpClient) { }

getLeaderboard(): Observable<leaderboardInstance[]>  {
console.log("leaderboardservice");
let url="ourAPIurl";

var salt = "1234"
var hash1 = SHA256(salt+"lalalala");

localStorage.setItem('methodName', 'GetMatchesOfGroup');
localStorage.setItem('userId', '2');
localStorage.setItem('token', String(hash1));
localStorage.setItem('id_group', '7');
localStorage.setItem('password', String(hash1));
localStorage.setItem('madCheck', 'bc8fcafb0829db3744d0aad45ebda03882d25367291de3883a8c7f75a9c45fb5');

const params = new HttpParams()
.set('methodName', localStorage.getItem('methodName'))
.set('userId', localStorage.getItem('userId'))
.set('token', localStorage.getItem('token'))
.set('id_group', localStorage.getItem('id_group'))
.set('password', localStorage.getItem('password'))
.set('madCheck', localStorage.getItem('madCheck'));

return this.http.post<leaderboardInstance[]>(url, params, {responseType: 'json'});

}
}

leaderboard.component.html

    <tbody>
    <tr *ngFor="let leaderboardInstance of leaderboard; index as i">
      <td width=25><div id="rank1">{{i+1}}</div></td>
      <td><a class="name-table">{{leaderboardInstance.name | uppercase}} {{leaderboardInstance.surname | uppercase | slice:0:1}}<span>.</span></a></td>
      <td class="played">{{leaderboardInstance.played}}</td>
      <td class="won">{{leaderboardInstance.wins}}</td>
      <td class="loses">{{leaderboardInstance.loses}}</td>
      <td class ="percentage" class="center">{{leaderboardInstance.percentage}}<span>%</span></td>
    </tr>
  </tbody>
  </table>
</div>

Upvotes: 1

Views: 78

Answers (2)

John
John

Reputation: 11409

Maybe the leaderboard-array is only updating its entries, not the list itself? Angular does not detect changes if you add or remove elements from the same list. You can use the answer provided here: https://stackoverflow.com/a/42962723/1471485, or you can recreate the list when you get the leaderboard:

this.leaderboard = [].concat(this.formatMatchesSingles(leaderboard));

using [].concat to create a new instance, and Angular will detect the change.

Upvotes: 0

Maximilian Riegler
Maximilian Riegler

Reputation: 23506

I think you want to get your component references via the ViewChild annotation and remove them from the constructor like that:

export class AppComponent{
    @ViewChild(MatchesComponent)
    private match_component: MatchesComponent;

    @ViewChild(LeaderboardComponent)
    private leaderboard_component: LeaderboardComponent;

    @ViewChild(ClubStatisticsComponent)
    private clubstatistics_component: ClubStatisticsComponent;

    constructor(){}

And also remove them from the providers array in your AppComponent. You usually only want services to be injected in the component like that.

Upvotes: 2

Related Questions