Michal Takac
Michal Takac

Reputation: 37

Iterate through nested objects in Meteor.js and insert results into table

I'm trying to make a RuneScape hiscores checker in Meteor.js. I'm now successfully parsing data from their API and saving it as object (you can see app in action here: http://rs-hiscores.meteor.com/). Here's my server code:

var cheerio = Meteor.npmRequire('cheerio');

var BASE_SKILLS = [ 
  'overall', 'attack', 'defence', 'strength', 'hitpoints', 'ranged',
  'prayer', 'magic', 'cooking', 'woodcutting', 'fletching', 'fishing',
  'firemaking', 'crafting', 'smithing', 'mining', 'herblore', 'agility', 
  'thieving', 'slayer', 'farming', 'runecrafting', 'hunter', 'construction'
];

var skills = {
  'osrs': BASE_SKILLS,
  'rs3': BASE_SKILLS.concat('summoning', 'dungeoneering', 'divination')
};

var urls = {
  'osrs': 'http://services.runescape.com/m=hiscore_oldschool/index_lite.ws?player=',
  'rs3': 'http://hiscore.runescape.com/index_lite.ws?player='
};

Meteor.methods({  
  lookup: function(player, game) {
    if (!urls.hasOwnProperty(game)) {
      game = 'rs3';
    }
    var url = urls[game].concat(encodeURIComponent(player));
    result = Meteor.http.get(url);
    $ = cheerio.load(result.content);
    body = $.html();
    parsed = Meteor.call('parseStats', body, skills[game]);
    return parsed;
  },
  parseStats: function(raw, skillsList) {
    var stats = raw.split('\n').slice(0, skillsList.length);
    var statsObj = { };
    stats.forEach(function(stat, index) {
      var chunk = stat.split(',');
      statsObj[skillsList[index]] = {
        rank: +chunk[0],
        level: +chunk[1],
        xp: +chunk[2]
      };
    });
    return statsObj;
  }
});

In my client code, I'm testing lookup method manually by providing player name inside function as an argument:

Meteor.call('lookup', 'zezima', 'rs3', function(error, result) {

  if (error) {
    console.error(error);
  }

  console.log(result);

  Session.set("data", result);

});

Template.rawdata.helpers({

  getData: function() {
    return Session.get("data");
  }

});

Result in console:

{
    agility: {
        level: 99,
        rank: 174,
        xp: 100234567
    },

    attack: {
        level: 99,
        rank: 601,
        xp: 127370193
    },

    construction: {
        level: 99,
        rank: 119,
        xp: 141170001
    },

    and so on...
}

Obviously, when I call getData inside my template in html and render it, it shows: [object Object]. So I want to somehow iterate through objects and insert them into table, that will look like this one:

<table id="rs-hiscores">
    <thead>
        <tr>
            <th>Skill name</th>
            <th>Rank</th>
            <th>Level</th>
            <th>Xp</th>
        </tr>
    </thead>
    <tbody id="rs-hiscore-data">
        <tr>
            <td>Agility</td>
            <td>99</td>
            <td>174</td>
            <td>109317063</td>
        </tr>
        <tr>
            <td>Attack</td>
            <td>99</td>
            <td>601</td>
            <td>127370193</td>
        </tr>
        <tr>
            <td>Construction</td>
            <td>99</td>
            <td>119</td>
            <td>141170001</td>
        </tr>

        ...and so on ...
    </tbody>
</table>

How can I do that? And also - whould it be possible to sort results in the same order as skills are inside BASE_SKILLS? Thank for help in advance.

Upvotes: 0

Views: 634

Answers (1)

Thaum Rystra
Thaum Rystra

Reputation: 749

Okay so you're going to need the data in a decent array, in the order of BASE_SKILLS, using Underscore to map the skills from your data to a new array, your getData helper should look like this:

var data = Session.get('data');
var array = _.map( BASE_SKILLS, function(skillName){
  var skill = data[skillName]
  return {
           name: skillName,
           rank: skill.rank,
           level: skill.level,
           xp: skill.xp
         };
});
return array;

This makes a neat array that looks like this:

[
  {
    name: "overall",
    rank: 99,
    level: 174,
    xp: 109317063
  },
  {
    name: "attack",
    rank: 23,
    level: 201,
    xp: 256311563
  },
  ...etc
]

Then you'll need to get those values into the html in the way you want.

<table id="rs-hiscores">
<thead>
    <tr>
        <th>Skill name</th>
        <th>Rank</th>
        <th>Level</th>
        <th>Xp</th>
    </tr>
</thead>
<tbody id="rs-hiscore-data">
  {{#each getData}}
    <tr>
      <td>{{name}}</td>
      <td>{{rank}}</td>
      <td>{{level}}</td>
      <td>{{xp}}</td>
    </tr>
   {{/each}}
</tbody>
</table>

You will have the lowercase keys in your table though, overall instead of "Overall" but to get nice names you can just make a dictionary helper function that swaps the one for the other like so: {{getNiceName name}}.

Upvotes: 1

Related Questions