Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Meteor findOne query returns undefined in one template helper. In other template helpers, same query works well

Suppose I have a Meteor collection called GameStatus. I have users with different roles, but I publish the GameStatus collection for all users. I simply use the following in server/publications.coffee

Meteor.publish 'gamestatus', ->
    GameStatus.find()

For two of the roles ('S' and 'B') I have no problem when I use the following Template helper (defined in files client/views/seller.coffee and client/views/buyer.coffee)

currentRound: ->
    return GameStatus.findOne().currentRound

For these I never get the following error.

Uncaught TypeError: Cannot read property 'currentRound' of undefined 

But for another role ('admin'), using the same template helper (defined in file client/views/admin.coffee) gives the above show Uncaught TypeError. It works if I instead write:

currentRound: ->
    return GameStatus.findOne()?.currentRound

I sort of understand why this works. I think, the collection is first not available when the page is being loaded, then it becomes available. But why does this not happen for other templates shown above?

Would really appreciate if someone can help clarify this.

like image 649
Curious2learn Avatar asked Jul 18 '13 15:07

Curious2learn


1 Answers

I believe exactly when a collection is ready won't always be consistent, so if you want to cover all your bases, always code for the case where a collection is not ready.

There's a quick-and-dirty way of dealing with collections that aren't ready, and a more sophisticated solution you can find in the todos example.

Quick and dirty solution would look like this.

currentRound: ->
  gameStatusrecord = GameStatus.findOne();
  if(gameStatusRecord) 
    gameStatusRecord.currentRound

This will work. Until the collection is ready, currentRound will return null, and your template will briefly render and probably just show a blank for current round. So not ideal user experience but not a huge deal.

For a more sophisticated solution, you can check whether a collection that you have subscribed is ready to be queried using the "ready" function. If a collection is not ready, you can render some other template, such as "loading", which guarantees that the currentRound helper won't ever be called until the collection is ready.

For instance, in the todos example, the client subscribes to the "lists" collection on line 24 of todos.js:

var listsHandle = Meteor.subscribe('lists', function () {

Then defines a helper function for the lists template on line 80 of todos.js

Template.lists.loading = function () {
  return !listsHandle.ready();
};

Then in the lists template in todos.html line 20, it doesn't try to render any templates unless the listsHandle is ready.

<h3>Todo Lists</h3>
{{#if loading}}
  <div id="lists">Loading...</div>
{{else}}
  <div id="lists">
    {{#each lists}}
    <!--etc.-->
like image 169
Jonathan Warden Avatar answered Nov 15 '22 00:11

Jonathan Warden