How to obtain data from server using a Meteor method in a Handlebars helper with Coffeescript?

2,922 views
Skip to first unread message

curiou...@gmail.com

unread,
Nov 14, 2013, 2:49:07 PM11/14/13
to meteo...@googlegroups.com
Please take a look at the following helper. It fails to return the data that I expect it to return. 

I think the problem is because of the implicit return in Coffeescript. Do you know how I can get this working (other than adding the data to a collection)?

Template.set4.helpers
    dataFromServer: () ->
        # Meteor method dataSet obtains some data which is an array of objects
        # The data is NOT in a collection.
        Meteor.call 'dataSet', (err, res) ->
            if err
                console.log err
            else
                records = res[1..]
                #console output in Chrome shows the data, which means 
                # server is sending data to the client.
                console.log records 
                return records 

I think because of the implicit return, Coffeescript is returning the entire Meteor.call..., which is undefined. It seems this must be easy to do, but I don't know how to get around this problem.

Thanks in advance for your help.

 

curiou...@gmail.com

unread,
Nov 15, 2013, 10:24:33 AM11/15/13
to meteo...@googlegroups.com
Okay, on thinking further it seems this is not a Coffeescript problem, but in general a Javascript issue where one cannot obtain return values from callbacks the way I am trying. 

I need to understand callbacks better to see how I can use the return value from a Meteor method call. The way appears to be passing a callback to the outer function. I am not sure whether something like that is possible in the case of Handlebar helper. Can someone please comment?

Thank you.

Tom DeHart

unread,
Nov 15, 2013, 10:52:00 AM11/15/13
to meteo...@googlegroups.com
You're right that you cannot return values from callbacks since the meteor method call was asynchronous. However it's hard to tell from your example what you're trying to accomplish since reactivity should take care of situations like these. If, for example, the method does an insert on a collection and you have a template that is rendering that collection then you don't need to 'return' data or even pass a callback, Meteor should know that the collection changed and re-render the template automatically.

A more complete example would help in giving further guidance.

curiou...@gmail.com

unread,
Nov 15, 2013, 10:45:24 PM11/15/13
to meteo...@googlegroups.com
Hello Tom,

I have included the Meteor method, which will clarify what I am trying to do. But essentially, I want to check on the server whether a specific condition is satisfied, and then return some data only if that condition is satisfied. Having thought about this further, I think I may be able to get the data, by publishing it only if the specific condition is satisfied (perhaps. along with using Deps.autorun() and subscriptions). However, after seeing that my original attempt (the code snippet in my first email in this thread) failed, now for the purpose of learning I want to know how the data for a handlebars helper can be obtained from the server using a Meteor.method call. 

The dataSet method on the server
    dataSet: () ->
        userid = Meteor.userId()
        if userid
            qids = QuestionSets.findOne({setName: 'Set3'}).set_qids
            if qids
                responses = UserResponses.find( { qid: {$in: qids}, userid: userid } ).fetch()
                # condition is that number of responses = number of questions
                if responses.length < qids.length
                    return 'you need to attempt all questions.'
                else # same number of attempts as responses (all attempted)
                    data = QuestionData.findOne({dataName: 'oneMachine'}).data
                    return data

curiou...@gmail.com

unread,
Nov 18, 2013, 10:41:30 AM11/18/13
to meteo...@googlegroups.com
Does no one have an answer to this? My question is very simple. I have data on the server in the form of an array of objects instead of within a collection.

I want to get this data to the client to display it on the page, only provided certain condition is satisfied. 
Is there no way of doing this without putting the data in a mongodb collection?

Andrew Mao

unread,
Nov 18, 2013, 4:03:05 PM11/18/13
to meteo...@googlegroups.com
Is there a reason you wouldn't want to put this array in a collection? That's kind of the whole point of Meteor - to eliminate manual back-and-forth juggling of data from the client to the server.

Ran Tavory

unread,
Nov 18, 2013, 4:48:12 PM11/18/13
to meteo...@googlegroups.com, meteo...@googlegroups.com
An easy solution is to use a collection. 

Another way is to use a subscription to a pseudo collection. Eg something that behaves like a collection but isn't backed by an actual mongo collection, lives in memory only. There's an example for this on docs.meteor.com when counting the number of items if a collection. (Search for counts-by-room)

A third option is to use a meteor method (or http call if talking to non meteor server) and save the result in a shared variable and use dependency.chanced() when data arrives. Hope this example helps https://github.com/rantav/devdev/blob/master/app/client/views/search.coffee
--
You received this message because you are subscribed to the Google Groups "meteor-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to meteor-talk...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Adrian Lanning

unread,
Nov 19, 2013, 10:20:36 AM11/19/13
to meteo...@googlegroups.com
To summarize, 

  * the original issue was timing/async related; by the time the Meteor method call's callback executed, the helper function had already returned

  * Meteor methods can return arrays.  You can think of Meteor method calls as regular AJAX calls from your client; the second parameter passed to the callback is the result.

  * Meteor method calls are not reactive and should generally not be called from within Template helper functions.  Typically Meteor methods are called in response to a user action, such as a button click.  

You can send data to the client using a method call but then you are in charge of displaying that to the user, just like with a normal AJAX call.

In your original example you have the Meteor.call in a template helper function.  If you called that helper from HTML code, ex. `<div>{{dataFromServer}}</div>`, the Meteor.call would execute every time the `set4` template was rendered.  This is probably not what you want since you have very little control over when the `set4` template is rendered (it will get re-rendered any time a reactive component changes) and you'd have to manually update DOM elements in the callback since the helper function has already completed.


As Andrew and Ran pointed out, collections are reactive and are designed to publish sub-sets of data while automatically keeping that data up-to-date.


On Monday, November 18, 2013 10:41:30 AM UTC-5, curiou...@gmail.com wrote:

curiou...@gmail.com

unread,
Nov 22, 2013, 1:01:49 PM11/22/13
to meteo...@googlegroups.com
Andrew, Ran and Adrian,

Thanks very much for your comments. 

Regarding why I wanted to do that; I wanted to know how it would be possible to get data in a template without using collections, possibly to save the load on the database. 

But Adrian's email raises several good points. I have been bitten by including Meteor Method in Template helper before and that is a bad idea. I thought of it at that time that Methods should be called only in response to user actions...I had forgotten about that. 

This and other points suggests that saving the load on the database (even for the parts of the application where I do not care about reactivity) is not worth the other problems that result from using Methods in Template helpers.

Thanks.
Reply all
Reply to author
Forward
0 new messages