I Hafid I Hafid - 4 months ago 13
Node.js Question

Jade template doesn't get the data passed from express

I know this questions has almost the same title but the issue is different.

I'm using Jade template engine v.1.11.0 built into latest Keystone.js release. In a controller, I query the data with two view.on('init') callbacks. First callback only queries one record and always passes. The second sometimes don't.

category.js

var keystone = require('keystone');
var async = require('async');
exports = module.exports = function (req, res) {

var view = new keystone.View(req, res);
var locals = res.locals;

// Init locals
locals.section = 'category';
locals.filters = {
category: req.params.category
};
locals.data = {
sections: [],
category: {}
};

// Load current category
view.on('init', function (next) {

var q = keystone.list('Category').model.findOne({
key: locals.filters.category
});

q.exec(function (err, result) {
locals.data.category = result;
locals.section = locals.data.category.name.toLowerCase();
next(err);
});
});


// Load sections
view.on('init', function (next) {
var q = keystone.list('Section').model.find().where('category').in([locals.data.category]).sort('sortOrder').exec(function(err, results) {

if (err || !results.length) {
return next(err);
}

async.each(results, function(section, next) {
keystone.list('Article').model.find().where('section').in([section.id]).sort('sortOrder').exec(function(err, articles){
var s = section;
if (articles.length) {
s.articles = articles;
locals.data.sections.push(s);
} else {
locals.data.sections.push(s);
}
});

}, function(err) {
console.log(locals.data.sections);
});

next(err);
});
});

view.render('category');
};


In my view, I should always get this passed:

sections: { _id: 574b909b43ff68163ed86bf2, publicTitle: 'Title 1', key: 'name-1', sortOrder: 3, name: 'Name 1', __v: 0, category: 574b8960947f45f034ac89b4, text: '', image: {} }

category: { _id: 574b8960947f45f034ac89b4, key: 'blabla', sortOrder: 1, name: 'Blabla', __v: 0, image: {} }


But 60% of the time, I get this:

sections:

category: { _id: 574b8960947f45f034ac89b4, key: 'johndoe', sortOrder: 1, name: 'JohnDoe', __v: 0, image: {} }


Strange thing is, If I go to another category, which has more sections and like 30 articles, I get sections 90% of the time, but still missing them 10%. This persists in both development and production.

Is some "next()" firing too early? I can't see where I messed up.

Answer

Alright. After some reading on async I managed to get it to work properly using async.parallel.

var keystone = require('keystone');
var async = require('async');
exports = module.exports = function (req, res) {

    var view = new keystone.View(req, res);
    var locals = res.locals;

    // Init locals
    locals.section = 'category';
    locals.filters = {
        category: req.params.category
    };
    locals.data = {
        sections: [],
        category: {}
    };

    // Load current category
    view.on('init', function (next) {

        var q = keystone.list('Category').model.findOne({
            key: locals.filters.category
        });

        q.exec(function (err, result) {
            locals.data.category = result;
            locals.section = locals.data.category.name.toLowerCase();
            getChildrenRecords(locals.data.category, next);
        });
    });


    function getChildrenRecords(category, next){

        var q = keystone.list('Section').model.find().where('category').in([category]).sort('sortOrder').exec(function(err, results) {

            if (err || !results.length) {
                return next(err);
            }

            callItems = [];

            for(var i = 0; i < results.length; i++) {
                var data = results[i];
                callItems.push(makeCallbackFunction(data));
            }

            function makeCallbackFunction(section) {
                return function (callback) {

                    keystone.list('Article').model.find().where('section').in([section.id]).sort('sortOrder').exec(function(err, articles){

                        if (err) return callback(err);

                        if (articles.length) { section.articles = articles; }
                            locals.data.sections.push(section);
                            callback();
                    });
                };
            }

            async.parallel(callItems, function(err, results){
                next(err);
            });
        });
    }


    // Render the view
    view.render('category');
};
Comments