Pass data to view

53 views
Skip to first unread message

Folivi Fofo

unread,
May 5, 2014, 6:47:59 PM5/5/14
to nod...@googlegroups.com
hi all,

I'm working on an app where I need to display user's facebook events.

The code below shows how to retrieve the users events and then perform a query to facebook api to retrieve more event details.

As you can see, the process is: retrieving the events, then get more details about each, push all into an array then pass the array to the view.

I fail in sending the array to the view and I believe it might have something to do with the asynchronous way of nodejs. Is this where the callback is needed?

How can I solve this?

Hope I'm clear.

Thanks for your help

index : function(req, res){
        graph.setAccessToken(req.user.token);
        var events = [];
        graph.get("/me/events?limit=500", {limit: 500},  function(err, rep) {
            for(key in rep["data"]){
                var query = "SELECT eid, name, creator, description, pic, pic_big, pic_cover, start_time, end_time FROM event WHERE eid=" + rep["data"][key].id;
                graph.fql(query, function(err, event_hash) {
                    var ev = event_hash["data"][0];                   
                    if (ev.creator.toString() == req.user.uid.toString()) {
                        events.push(ev);
                    };                                       
                })                               
            };
        });               
        res.view({
            events: events
        });           
       
    },

Angel Java Lopez

unread,
May 5, 2014, 8:17:51 PM5/5/14
to nod...@googlegroups.com
You must execute the res.view AFTER retrieving the data in the callback. My first guess in your case:

index : function(req, res){
        graph.setAccessToken(req.user.token);
        var events = [];
        graph.get("/me/events?limit=500", {limit: 500},  function(err, rep) {
            for(key in rep["data"]){
                var query = "SELECT eid, name, creator, description, pic, pic_big, pic_cover, start_time, end_time FROM event WHERE eid=" + rep["data"][key].id;
                graph.fql(query, function(err, event_hash) {
                    var ev = event_hash["data"][0];                    
                    if (ev.creator.toString() == req.user.uid.toString()) {
                        events.push(ev);
                    };                             
           
                    res.view({
        
                events: events
                    });            

                })                                
            };
        });                
 
        
    },


--
Job board: http://jobs.nodejs.org/
New group rules: https://gist.github.com/othiym23/9886289#file-moderation-policy-md
Old group rules: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
---
You received this message because you are subscribed to the Google Groups "nodejs" group.
To unsubscribe from this group and stop receiving emails from it, send an email to nodejs+un...@googlegroups.com.
To post to this group, send email to nod...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/nodejs/b1f3b685-f439-4a19-9923-4d73416f6c03%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Aria Stewart

unread,
May 5, 2014, 8:10:59 PM5/5/14
to nod...@googlegroups.com
On May 5, 02014, at 18:47, Folivi Fofo <ab.f...@gmail.com> wrote:

hi all,

I'm working on an app where I need to display user's facebook events.

The code below shows how to retrieve the users events and then perform a query to facebook api to retrieve more event details.

As you can see, the process is: retrieving the events, then get more details about each, push all into an array then pass the array to the view.

I fail in sending the array to the view and I believe it might have something to do with the asynchronous way of nodejs. Is this where the callback is needed?

How can I solve this?


Indeed: you’ll want to send the view after the events.push — that happens at the innermost, not bottommost code in what you’ve written.


Hope I'm clear.

Thanks for your help

index : function(req, res){
        graph.setAccessToken(req.user.token);
        var events = [];
        graph.get("/me/events?limit=500", {limit: 500},  function(err, rep) {
            for(key in rep["data"]){
                var query = "SELECT eid, name, creator, description, pic, pic_big, pic_cover, start_time, end_time FROM event WHERE eid=" + rep["data"][key].id;
                graph.fql(query, function(err, event_hash) {
                    var ev = event_hash["data"][0];                   
                    if (ev.creator.toString() == req.user.uid.toString()) {
                        events.push(ev);
                    };                                       
                })                               
            };
        });               
        res.view({
            events: events
        });           
       
    },


signature.asc

Ryan Schmidt

unread,
May 5, 2014, 8:50:50 PM5/5/14
to nod...@googlegroups.com

On May 5, 2014, at 17:47, Folivi Fofo wrote:

> I'm working on an app where I need to display user's facebook events.
>
> The code below shows how to retrieve the users events and then perform a query to facebook api to retrieve more event details.
>
> As you can see, the process is: retrieving the events, then get more details about each, push all into an array then pass the array to the view.
>
> I fail in sending the array to the view and I believe it might have something to do with the asynchronous way of nodejs. Is this where the callback is needed?
>
> How can I solve this?
>
> Hope I'm clear.
>
> Thanks for your help
>
> index : function(req, res){
> graph.setAccessToken(req.user.token);
> var events = [];
> graph.get("/me/events?limit=500", {limit: 500}, function(err, rep) {

Here you are calling the graph.get function, and passing it a callback (the function(err, rep) {…} function) and telling it you would like it to call that function when it has finished getting the graph.

> for(key in rep["data"]){
> var query = "SELECT eid, name, creator, description, pic, pic_big, pic_cover, start_time, end_time FROM event WHERE eid=" + rep["data"][key].id;
> graph.fql(query, function(err, event_hash) {

And here, for each item returned from graph.get, you are calling graph.fql, and again telling it to call a callback (function(err, event_hash) {…}) when it is complete.

> var ev = event_hash["data"][0];
> if (ev.creator.toString() == req.user.uid.toString()) {
> events.push(ev);
> };
> })
> };
> });
> res.view({
> events: events
> });

Here you are responding with the view, right after having called graph.get, which is before graph.get has completed, which is before you call graph.fql, which is before graph.fql completes, which is before the callbacks have run, which is before you have pushed things onto the events array. So your view is rendered with an empty array.

You need to wait until all the callbacks have finished before calling res.view.

One way to do this is to keep a counter of how many tasks you need to complete, and decrement it when each task finishes; when the counter reaches 0, you can render the view.


index : function(req, res){
graph.setAccessToken(req.user.token);
var events = [];
graph.get("/me/events?limit=500", {limit: 500}, function(err, rep) {
var tasks = 0;
for(key in rep["data"]){
++tasks;
var query = "SELECT eid, name, creator, description, pic, pic_big, pic_cover, start_time, end_time FROM event WHERE eid=" + rep["data"][key].id;
graph.fql(query, function(err, event_hash) {
var ev = event_hash["data"][0];
if (ev.creator.toString() == req.user.uid.toString()) {
events.push(ev);
};
if (--tasks == 0) {
res.view({
events: events
});
}
})
};
});
},


However, the above assumes no error will ever occur, which is not likely. You need to consider what should happen when an error occurs 1) from graph.get(); 2) from any of the graph.fql() calls. Do you wish to call the view with an error object instead of the events object? If so, then you need to write code to do that, everywhere an error could occur (i.e. in every callback that’s given an err parameter).

There are libraries (npm modules) that can help you manage your control flow, if you don’t want to do it manually as described above. async is a popular one but there are many others. Consider taking some hours to play with various control flow libraries to see how they work and evaluate if any of them makes enough sense to you to warrant using it in your project.


Folivi Fofo

unread,
May 6, 2014, 1:34:51 AM5/6/14
to nod...@googlegroups.com
Thanks to all for your replies,

@ajilopez: calling res.view inside a loop causes sending multiple http header issue
@ryandesign your solution works perfectly

I'm still looking for a full tutorial on how to create functions with callbacks in nodejs though.
Cheers

Bruno Jouhier

unread,
May 6, 2014, 2:41:45 AM5/6/14
to nod...@googlegroups.com
Also, you should test the err parameter at the beginning of every callback, and do something if it is not null: log it, throw it, pass it to an another callback, etc. Don't ignore it.

Bruno
Reply all
Reply to author
Forward
0 new messages