2

I have a leaderboard in my ionic app, where I show the position of each registered user, the usernames and the points that the users earned.

Usernames and points are stored into the database, instead, I define the position printing an index for each user for all the list that contains the users.

I want be able also to show, at the bottom of the leaderboard, the position of the logged user, like in the image:

enter image description here

in the example, if YYY it's logged I want show "USER in position 2"

How can I, with my code, retrieve user position (maybe store it in a variable) and show it on html? it is possible?

rank.ts (the function that create my leaderbord list)

   this.itemRef.orderByChild("total_points").on('value',itemSnapshot =>{
    this.items = [];
    itemSnapshot.forEach( itemSnap => {
      this.items.push(itemSnap.val());
      return false;
    });
    return this.items.reverse(); 
  });

rank.html

<ion-content padding>
<ion-card>
    <ion-card-header class ="centered" id="header_classifica" > 
        <div > USER you are in position XXX</div>
  </ion-card-header>

    <div id="table">
        <div class="row header">
            <div class="col classifica"> <b class="voci_table_header"> Posizione</b></div>
            <div class="col classifica"> <b class="voci_table_header"> Username</b></div>
            <div class="col classifica"> <b class="voci_table_header"> Punti</b></div>

        </div>

        <div class="row" *ngFor="let item of items; let i = index">
            <div class="col classifica">{{i + 1}}</div>
            <div class="col classifica">{{ item.username }} </div>
            <div class="col classifica">{{ item.total_points }} </div>
        </div>

    </div>
</ion-card>

</ion-content>

I hope that my problem it's clear. Thank you in advance.

EDIT: SOLVED PROBLEM USING THIS CODE

 this.itemRef.orderByChild("total_points").on('value',itemSnapshot =>{
      this.items = [];
      itemSnapshot.forEach( itemSnap => {
        this.items.push(itemSnap.val());
        return false;
      });
      var j = 0;
      this.items.reverse().forEach(i=>{
        j++;
        if (new String(i.username).valueOf() == new String(this.username).valueOf()){
          console.log("Trovato")
          this.position = j;
        }
      })

      return this.items; 
    });
JEricaM
  • 794
  • 2
  • 15
  • 37
  • U need to reorder your list based on user points or you need to store this data one the phone not on firebase ? can you explain please in couple of words your problem, because your title say without using firebase and in your question you ask how to do it in firebase – Farouk Elkholy Nov 23 '17 at 09:57
  • I need to show the position of the logged user ( {{username}} retrieve this date) and show it in: USER you are in position XXX. so I want have "{{username}} you are in position {{position}}". Without firebase I mean that my position data is not into firebase. If it's ambiguous I can change it. – JEricaM Nov 23 '17 at 10:01
  • I got what you want to do :) but not what the difficulties you face :) – Farouk Elkholy Nov 23 '17 at 10:03
  • I don't know, with my code, how to show the user position. How can I retrieve this information with my firebase query and create a variable "position" that I can use into html? I'm stuck here (I'm a firebase newbie and I don't find a lot of usefull guides :( ) – JEricaM Nov 23 '17 at 10:04
  • Okay, I start to get it :)you want to show your logged in user which ranking(position) comparing to other users, for example your points is 150 and your rabnking(position) is 3. Last question, you want this comparison to be between logged in user or with all users in general ? – Farouk Elkholy Nov 23 '17 at 10:07
  • I want the position in the global leaderboard, with all users in general. If in the leaderboard MINNIE (logged user) it's in position 4, I want show "MINNIE you are in position 4". Hope it's clear, sorry for my english but I'm italian ^^. and thank you a lot for you help – JEricaM Nov 23 '17 at 10:10
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/159666/discussion-between-jericam-and-farouk-el-kholy). – JEricaM Nov 23 '17 at 10:22
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/159671/discussion-between-jericam-and-farouk-el-kholy). – JEricaM Nov 23 '17 at 10:58

1 Answers1

0

I will give you a simple solution.

Info: The solution is working fine if you have small amount of users(200 for example) due the overhead of fetching all your users on a mobile memory.(It will work fine with any number of users anyway but it is not required to fetch a lot of data in the mobile memory)

We will fetch all the users then we will reorder them based on their Points so our *ngFor in your template will assign the position right and we will have a variable to store the position of the current user accessing the rank page so we can bind in the selector.

1)Create a service:

First We will create a service to do so.

Info: creating a service so we can inject it in any component that need to access this sorted array and this current user.Create for example user.service.ts file. (I think your method orderByChild can work but i didn't used before so can't tell).

import {Injectable} from '@angular/core';
import 'rxjs/add/operator/map';
import {Http,Response} from '@angular/http';


@Injectable()
export class UserService {

sortedArray: Array <{username: string,total_points: Number}>;
currentUserPosition:Number;
    constructor(private http: Http) {

    }

getUsers(){

   let items: Array <{username: string,total_points: Number}>;

   this.itemRef.on('value',itemSnapshot =>{ // you need to define your item Ref as a global variable in this service
    itemSnapshot.forEach( itemSnap => {
      this.items.push(itemSnap.val());
    });
     this.sortUsers(items);
  });
}

sortUsers(users) {
    this.sortedArray = users.sort(function(a, b) {
       return b.total_points - a.total_points // descending
       //return a.total_points - b.total_points // accending
    });
}

getUserPosition(user){ 
    this.currentUserPosition = this.sortedArray.map(function (x) { return x.username}).indexOf(user.username);
}

}

2)Rank.ts

import {UserService} from '<path>/user.service';


constructor(public userService:UserService){
   this.userService.getUsers();
   this.userService.getUserPosition(user); // you need to pass the user accessing the rank page
}

3)Rank.html

<ion-card-header class ="centered" id="header_classifica" > 
        <div > USER you are in position {{userService.currentUserPosition + 1}}</div>
  </ion-card-header>

<div class="row" *ngFor="let item of userService.sortedArray; let i = index"> // we are accessing the sorted array defined in the service
    <div class="col classifica">{{i + 1}}</div>
    <div class="col classifica">{{ item.username }} </div>
    <div class="col classifica">{{ item.total_points }} </div>
</div>
Farouk Elkholy
  • 913
  • 7
  • 10
  • thank you so much. I'll try asap. :) Only one question, the service code need to be in a different file from rank.ts? – JEricaM Nov 23 '17 at 11:19
  • You are welcome :) No you can have it in the same folder but if you want to resuse this service, it is required to create a folder "services" in same level of your pages folder and create your user service file in it, so you can reuse this service in other components – Farouk Elkholy Nov 23 '17 at 11:21
  • thank you for the information :D as soon as I can try it I'll update you! – JEricaM Nov 23 '17 at 11:27
  • I wrote in chat for some questions – JEricaM Nov 23 '17 at 11:43
  • I still thank you for your help, but the code did not help me since it was not practical to use it and I did not return it as required. I solved it in a much simpler way. – JEricaM Nov 24 '17 at 16:32