Как установить несколько res.locals, извлеченных из разных коллекций БД?(Экспресс, Монго, EJS) - PullRequest
0 голосов
/ 02 апреля 2019

Я пытался очистить свой код app.js и подогнать все res.locals, полученные из БД, в один метод app.use.В тот момент, когда я сделал это, мое приложение упало с ошибкой, что один из 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 голосов
/ 02 апреля 2019

Причина в том, что вы вызываете 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(); 
        });  
    }); 
});
...