将动态内容集成到Sails.JS应用程序中的layout.ejs文件的正确方法是什么?

时间:2013-11-28 13:31:50

标签: sails.js

说我在Sails.js写了一个博客应用程序。

在此应用中的每个页面上,有一个名为“Recent Posts”的侧边栏小部件,其中列出了5个最新帖子的标题,点击它们会将您带到相关帖子

由于此侧边栏窗口小部件位于每个页面上,因此它应位于layout.ejs中。但是,这里我们有一个冲突 - 动态内容只应该在控制器动作中从数据库中提取以呈现特定视图。

动态内容不适用于特定视图,而是适用于整个网站(通过layout.ejs)。

根据我所理解的约定,我必须在呈现视图的每个控制器操作中获取侧边栏小部件的动态内容数据(否则当我尝试时会出现未定义的错误在我的layout.ejs文件中调用本地。)

我尝试/考虑的事情:

  • 将动态内容加载到呈现视图的每个控制器操作(此解决方案非常糟糕)并在layout.ejs中调用该动态内容,就好像它是特定于本地的视图。这很好,但是反对D.R.Y.原则并且坦率地说,在每个控制器操作中必须对数据库运行相同的查询是一种痛苦。

  • 根据另一个类似的stackoverflow问题,创建一个新配置(EG config/globals.js),将我的数据库中的动态内容作为变量加载到该配置文件中,然后调用sails.config.globals.[variable_name] in我的layout.ejs文件。这也很有效,因为显然配置变量在应用程序的任何地方都可用 - 但它是一个我不喜欢的hacky解决方案(我加载的内容只是最近5篇帖子的标题和slu ,,而不是“全局配置选项”,正如解决方案所暗示的那样。)

  • 运行查询以直接在某些<% %>标记之间获取.EJS文件中的动态内容。我不确定这是否会起作用,但即使它确实如此,也违背了关注点的分离MVC原则,我想尽可能避免这样做(如果它可行的话)。

    < / LI>
  • 根据冗长的IRC讨论@ http://webchat.freenode.net/?channels=sailsjs,建议创建一个策略并将该策略映射到我的所有控制器。在该策略中,查询数据库中最近的5个帖子,并将它们设置为req.recentposts。这个解决方案的问题在于,虽然最近的帖子数据将传递给每个控制器,但我仍然必须将req.recentposts数据传递给我的视图 - 这样我仍然需要修改每个res.view({在每一个动作中。我不必在每个操作中都有数据库查询,这很好,但我仍然需要为呈现视图的每个操作添加一行代码......这不是D.R.Y.我正在寻找更好的解决方案。

那么,什么是正确的解决方案,而无需在每个控制器操作中加载该动态内容(一种坚持DRY的解决方案)是我正在寻找的,为我的layout.ejs文件提供一些动态内容?

2 个答案:

答案 0 :(得分:5)

在文件夹/ config中,您应该创建一个文件express.js并添加类似的内容:

module.exports.express = {
    customMiddleware: function(app){
        app.use(function(req, res, next){
            // or whatever query you need
            Posts.find().limit(5).exec(function(err, posts){
                res.locals.recentPosts = posts;
                // remember about next()
                next();
            });
        });
    }
}

然后在你的视图中做一些简单的循环:

<% for(var i=0; i<recentPosts.length; i++) { %>
    <% recentPosts[i].title %>
<% } %>

以下是文档中正确位置的一些链接: https://github.com/balderdashy/sails-docs/blob/0.9/reference/Configuration.md#expresshttps://github.com/balderdashy/sails-docs/blob/0.9/reference/Response.md#reslocals

答案 1 :(得分:1)

我发现了另一种方法。我所做的是创建一个服务,通过简单地利用已经在sails中的ejs库,可以将.ejs文件呈现为纯HTML。该服务既可以由控制器调用,也可以作为函数在本地传递,并从.ejs中执行。名为TopNavBarService的服务如下所示:

var ejs = require('ejs');
exports.render = function() {
    /* database finds goes here */
    var userInfo = {
        'username' : 'Kallehopp',
        'real_name' : 'Kalle Hoppson'
    };
    var html = null;
    ejs.renderFile('./views/topNavBar.ejs', {'locals':userInfo}, function(err, result) { html = result; });
    return html;
}

在constroller中它可能看起来像:

module.exports = {
    testAction: function (req, res) {
        return res.view('testView', {
            renderNavbar: TopNavBarService.render // service function as a local!
        });
    }
};

通过这种方式,您可以创建自定义的ejs-helper甚至可以获取参数(尽管此处未显示)。调用时,帮助程序可以访问数据库并呈现html的一部分。

<div>
    <%- renderNavbar() %>
</div>