Search code examples
javascriptmeteorcoffeescriptmeteor-blaze

Meteor helper not running reactively


I am using the mizzao:user-status package to make a list of online users.

Note that the following code is coffeescript, which has been working fine especially since I'm sticking with Blaze instead of React (I haven't found a way to use JSX in coffeescript).

Tangent aside, I'm specifically having an issue with the users.helpers in client.coffee. The debugger is only called once, and when I inspect the users_data variable in there it shows an empty array. It's clear that at least some part of this is working reactively, since when I continue past the breakpoint and check the value of users_data again, it is nonempty. But the return value of the users helper does not seem to change. The function doesn't re-run.

tl;dr

how to make the users helper method rerun when users_data changes

# ------------------
# server.coffee
# ------------------

Meteor.publish 'user_status', ->
  Meteor.users.find(
    { "status.online": true },
    fields: {}
  )

# ------------------
# client.coffee
# ------------------

Meteor.subscribe 'online_users'
users = Template.users
users.helpers
  users: ->
    window.users_cursor = Meteor.users.find
      "status.online": true
    window.users_data = users_cursor.collection._docs._map
    debugger
    window.final = Object.keys(users_data).map (_id) =>
      user = users_data[_id]
      {
        _id,
        name: user.profile.name
      }
    final

and the relevant part of the Blaze template:

<body>
  <h1>Welcome to Meteor!</h1>
  {{> loginButtons }}
  {{> users}}
</body>

<template name="users">
  {{#each users}}
    <li>{{_id}}</li>
  {{/each}}
</template>

Solution

  • Thankfully, it's not a bug in Meteor itself and wasn't too difficult to correct.

    This whole thing was unnecessary:

      users: ->
        window.users_cursor = Meteor.users.find
          "status.online": true
        window.users_data = users_cursor.collection._docs._map
        debugger
        window.final = Object.keys(users_data).map (_id) =>
          user = users_data[_id]
          {
            _id,
            name: user.profile.name
          }
        final
    

    Instead this suffices:

    users: ->
      Meteor.users.find({})
    

    The Meteor.users.find result is not an array and doesn't respond to [0] style indexing, which is why I didn't think that it would be suitable as a return value for the helper. However it does respond to forEach. That's why it works with the following refactor of the template:

    <template name="users">
      {{#each user in users}}
        <li>{{user._id}</li>
      {{/each}}
    </template>
    

    The one problem remaining is that Meteor.users.find("status.online": true) doesn't work still, it must be find({}) instead. I'll work on that and possibly post a question about it.