如何设置从数据库的不同集合中检索到的几个res.locals? (Express,Mongo,EJS)

时间:2019-04-02 14:04:11

标签: node.js mongodb express ejs

我试图清理我的app.js代码,并在一个app.use方法中适合从数据库检索到的所有res.locals。我这样做的那一刻,我的应用程序崩溃了,错误是未定义res.locals,从而阻止了嵌套在另一个视图(标题)中的ejs视图(navbar)的呈现。

如果我这样设置全局变量,一切都会很好

//app.js

var express          = require("express"),
    app              = express(),
    ...
    ...

// DB models import
var TranslationService = require("./models/translationservice"),
    Language = require("./models/language"),
    User    = require("./models/user");

// ROUTES import (+ use at the bottom!)
var indexRoutes = require("./routes/index.js"),
    translationServiceRoutes = require("./routes/translationservice.js"),
    languageRoutes = require("./routes/language.js")

// APP config
...
// USER PASSPORT config
...

app.use(function(req,res,next){
    res.locals.currentUser = req.user;
    res.locals.success = req.flash('success');
    res.locals.error = req.flash('error');   
    next();
});

app.use(function(req,res,next){
    TranslationService.find({}, function(err, foundItem) {
        if (err || !foundItem) {
            console.log(err);
        } else {
            res.locals.translationServiceData = foundItem;
            next();
        }   
    });
});

app.use(function(req,res,next){
    Language.find({}, function(err, foundItem) {
        if (err || !foundItem) {
            console.log(err);
        } else {
            res.locals.languageData = foundItem;
            next();
        }   
    });
});

// ROUTES use
app.use("/", indexRoutes);
app.use("/languages", languageRoutes);
app.use("/translation-services", translationServiceRoutes);

server.listen(3000, function () {
   console.log("server has started");
});

我想使我的代码更加干燥,并将所有res.locals合并为一个app.use方法。像这样:

app.use(function(req,res,next){
    res.locals.currentUser = req.user;
    res.locals.success = req.flash('success');
    res.locals.error = req.flash('error');  

    TranslationService.find({}, function(err, foundItem) {
        if (err || !foundItem) {
            console.log(err);
        } else {
            res.locals.translationServiceData = foundItem;
        }   
    });

    Language.find({}, function(err, foundItem) {
        if (err || !foundItem) {
            console.log(err);
        } else {
            res.locals.languageData = foundItem;
        }   
    });

    next();
});

一旦我这样做,我就会得到一个错误。但是,如果我多次重新加载页面,则有时会呈现视图。我想如果发生错误,则会在从数据库检索res.locals之前呈现视图。

ReferenceError: /Users/.../views/contact.ejs:5
    3| 
    4| <% include partials/head %>
 >> 5| <% include partials/header %>
    6| 
    7| <!-- Page Title
    8| ============================================= -->

/Users/.../views/partials/header.ejs:21
    19|             ============================================= -->
    20| 
 >> 21|             <% include ../partials/navbar %>
    22| 
    23|             <!-- #primary-menu end -->
    24|         </div>

/Users/.../views/partials/navbar.ejs:5
    3|         <li><a href="/translation-services"><div class="on-click">Translation</div></a>
    4|             <ul>
 >> 5|                 <% translationServiceData.sort((a, b) => a.slug.localeCompare(b.slug)); %>
    6|                 <% translationServiceData.forEach(function(item){ %>
    7|                 <li><a href="/translation-services/<%= item.slug %>"><div class="on-click"><%= item.slug %> translation</div></a></li>
    8|                 <% }); %>

translationServiceData is not defined

我认为这与节点js异步加载有关,但是我不确定,我也不知道如何解决此问题。也许使用res.locals来构建导航栏是一个过大的杀伤力,必须采取另一种方式。任何帮助表示赞赏。

1 个答案:

答案 0 :(得分:0)

原因是您在从数据库获取任何数据之前正在调用next()。

app.use(function(req,res,next){
    res.locals.currentUser = req.user;
    res.locals.success = req.flash('success');
    res.locals.error = req.flash('error');  

    TranslationService.find({}, function(err, foundItem) {
        if (err || !foundItem) {
            console.log(err);
        } else {
            res.locals.translationServiceData = foundItem;
        }   
    });

    Language.find({}, function(err, foundItem) {
        if (err || !foundItem) {
            console.log(err);
        } else {
            res.locals.languageData = foundItem;
        }   
    });

    //res.locals.translationServiceData and res.locals.languageData
    //are still undefined because the above db calls haven't returned any data yet
    //since the db calls are asynchronous
    next();
});

最简单的解决方案是这个

app.use(function(req,res,next){
    res.locals.currentUser = req.user;
    res.locals.success = req.flash('success');
    res.locals.error = req.flash('error');  

    TranslationService.find({}, function(err, foundItem) {
        if (err || !foundItem) {
            console.log(err);
        } else {
            res.locals.translationServiceData = foundItem;
        } 

        Language.find({}, function(err, foundItem) {
            if (err || !foundItem) {
                console.log(err);
            } else {
                res.locals.languageData = foundItem;
            }  

            // call next once you have all the data
            next(); 
        });  
    }); 
});