1

I'm trying to use the Steam Community (steamcommunity) npm package along with meteorhacks:npm Meteor package to retreive a user's inventory. My code is as follows:

lib/methods.js:

Meteor.methods({
  getSteamInventory: function(steamId) {
    // Check arguments for validity
    check(steamId, String);

    // Require Steam Community module
    var SteamCommunity = Meteor.npmRequire('steamcommunity');
    var community = new SteamCommunity();

    // Get the inventory (730 = CSGO App ID, 2 = Valve Inventory Context)
    var inventory = Async.runSync(function(done) {
      community.getUserInventory(steamId, 730, 2, true, function(error, inventory, currency) {
        done(error, inventory);
      });
    });

    if (inventory.error) {
      throw new Meteor.Error('steam-error', inventory.error);
    } else {
      return inventory.results;
    }
  }
});

client/views/inventory.js:

Template.Trade.helpers({
  inventory: function() {
    if (Meteor.user() && !Meteor.loggingIn()) {
      var inventory;
      Meteor.call('getSteamInventory', Meteor.user().services.steam.id, function(error, result) {
        if (!error) {
          inventory = result;
        }
      });

      return inventory;
    }
  }
});

When trying to access the results of the call, nothing is displayed on the client or through the console.

I can add console.log(inventory) inside the callback of the community.getUserInventory function and receive the results on the server.

Relevant docs:

troytc
  • 662
  • 1
  • 7
  • 28

2 Answers2

2

You have to use a reactive data source inside your inventory helper. Otherwise, Meteor doesn't know when to rerun it. You could create a ReactiveVar in the template:

Template.Trade.onCreated(function() {
  this.inventory = new ReactiveVar;
});

In the helper, you establish a reactive dependency by getting its value:

Template.Trade.helpers({
  inventory() {
    return Template.instance().inventory.get();
  }
});

Setting the value happens in the Meteor.call callback. You shouldn't call the method inside the helper, by the way. See David Weldon's blog post on common mistakes for details (section Overworked Helpers).

Meteor.call('getSteamInventory', …, function(error, result) {
  if (! error) {
    // Set the `template` variable in the closure of this handler function.
    template.inventory.set(result);
  }
});
klaussner
  • 2,364
  • 3
  • 25
  • 33
  • 1
    I've done this, and opted to perform the ```Meteor.call``` in the ```onCreated``` callback, however I'm still not getting anything on the client. I have followed the answer to [this question](https://stackoverflow.com/questions/22147813/how-to-use-meteor-methods-inside-of-a-template-helper), as suggested in David Weldon's post. – troytc Jan 04 '16 at 00:10
2

I think the issue here is you're calling an async function inside your getSteamInventory Meteor method, and thus it will always try to return the result before you actually have the result from the community.getUserInventory call. Luckily, Meteor has WrapAsync for this case, so your method then simply becomes:

Meteor.methods({
  getSteamInventory: function(steamId) {
    // Check arguments for validity
    check(steamId, String);

    var community = new SteamCommunity();
    var loadInventorySync = Meteor.wrapAsync(community.getUserInventory, community);

    //pass in variables to getUserInventory
    return loadInventorySync(steamId,730,2, false);
  }
});

Note: I moved the SteamCommunity = Npm.require('SteamCommunity') to a global var, so that I wouldn't have to declare it every method call.

You can then just call this method on the client as you have already done in the way chris has outlined.

Jon
  • 493
  • 1
  • 4
  • 14
  • 1
    That small ```Meteor.wrapAsync``` over ```meteorhacks:npm```'s version of the function makes all the difference, coupled with the rest of @chrisklaussner 's answer :) – troytc Jan 04 '16 at 20:53