最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

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

programmeradmin4浏览0评论

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 bees available. But why does this not happen for other templates shown above?

Would really appreciate if someone can help clarify this.

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 bees available. But why does this not happen for other templates shown above?

Would really appreciate if someone can help clarify this.

Share Improve this question asked Jul 18, 2013 at 15:55 Curious2learnCurious2learn 33.6k43 gold badges110 silver badges126 bronze badges 3
  • When you subscribe to the collection, in the call back log something to the console so you know when it is available, and do the same thing with the call that it is failing. That way you can test your hypothesis. – 1321941 Commented Jul 18, 2013 at 16:02
  • @MrD Can you please give me an example? What should I log that would help me know when the subscription bees available. It seems it is only for this specific role that they are not available initially. – Curious2learn Commented Jul 18, 2013 at 16:28
  • You want to do something like this for your subscribe gist.github./devonbarrett/b698c10cc427ee2c1811 and then log something similar for the currentRound function and see if it is getting fired off before the collection is ready – 1321941 Commented Jul 18, 2013 at 16:37
Add a ment  | 

1 Answer 1

Reset to default 14

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.-->

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论