在Sails.JS应用程序中将动态内容集成到layout.ejs文件中的正确方法是什么?
假设我在Sails.js中写了一个博客应用程序 在这个应用程序的每个页面上,都有一个名为“最近的帖子”的边栏小部件,它列出了最近5篇帖子的标题,点击它们,你就会看到有问题的帖子 因为每个页面上都有这个边栏小部件,所以它应该在在Sails.JS应用程序中将动态内容集成到layout.ejs文件中的正确方法是什么?,sails.js,Sails.js,假设我在Sails.js中写了一个博客应用程序 在这个应用程序的每个页面上,都有一个名为“最近的帖子”的边栏小部件,它列出了最近5篇帖子的标题,点击它们,你就会看到有问题的帖子 因为每个页面上都有这个边栏小部件,所以它应该在layout.ejs中。但是,这里我们有一个冲突-动态内容只应该在控制器操作中从数据库中提取,以呈现特定视图 此动态内容不是针对特定视图,而是针对整个站点(通过layout.ejs) 按照我所理解的惯例,我必须在呈现视图的每个控制器操作中获取侧边栏小部件的动态内容数据(否则,
layout.ejs
中。但是,这里我们有一个冲突-动态内容只应该在控制器操作中从数据库中提取,以呈现特定视图
此动态内容不是针对特定视图,而是针对整个站点(通过layout.ejs)
按照我所理解的惯例,我必须在呈现视图的每个控制器操作中获取侧边栏小部件的动态内容数据(否则,当我试图在layout.ejs文件中调用该本地控件时,我将得到一个未定义的错误)
我尝试/考虑过的事情:
- 在呈现视图的每个控制器操作中加载该动态内容(此解决方案非常糟糕),并在layout.ejs中调用该动态内容,就像它是特定视图的本地内容一样。这很好,但违背了D.R.Y.的原则,坦率地说,在每个控制器操作中都必须对数据库运行相同的查询,这是一种痛苦
- 根据另一个类似的stackoverflow问题,创建一个新配置(例如
),将我的动态内容作为变量从数据库加载到该配置文件中,然后在我的layout.ejs文件中调用config/globals.js
。这也行得通,因为很明显,配置变量在应用程序中随处可见——但这是一个我不喜欢的黑客解决方案(我加载的内容只是最近5篇文章的标题和片段,而不是解决方案所暗示的“全局配置选项”)sails.config.globals.[variable\u name]
- 运行查询以直接在一些
标记之间获取.EJS文件中的动态内容。我不确定这是否可行,但即使可行,这也违背了关注点分离MVC原则,我希望尽可能避免这样做(如果可行的话) - 根据IRC冗长的讨论@,建议创建一个策略并将该策略映射到我的所有控制器。在该策略中,查询数据库中最近的5篇文章,并将它们设置为req.recentposts。这个解决方案的问题是,虽然最近的posts数据将传递给每个控制器,但我仍然必须将req.recentposts数据传递给我的视图——这样我仍然必须修改每个操作中的每个res.view({})。我不必在每个操作中都使用数据库查询,这很好,但我仍然需要在每个呈现视图的操作中添加一行代码。。。这不是D.R.Y.我在寻找更好的解决方案
那么,什么是正确的解决方案,而不需要在每个控制器操作中加载动态内容(我正在寻找符合D.R.Y.的解决方案),要在文件夹/config中获得一些可用于my layout.ejs文件的动态内容,您应该创建一个文件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 %>
<% } %>
我找到了另一种方法。我所做的是创建一个服务,通过简单地利用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;
}
module.exports = {
testAction: function (req, res) {
return res.view('testView', {
renderNavbar: TopNavBarService.render // service function as a local!
});
}
};
在CONTROLLER中,它可能看起来像:
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;
}
module.exports = {
testAction: function (req, res) {
return res.view('testView', {
renderNavbar: TopNavBarService.render // service function as a local!
});
}
};
通过这种方式,您可以创建定制的ejs帮助器,它甚至可以接受参数(尽管这里没有显示)。调用时,助手可以访问数据库并呈现html的一部分
<div>
<%- renderNavbar() %>
</div>
这将允许从任何视图(包括layout.ejs)中访问res.locals.recentPosts,而无需在任何控制器中添加代码(以某种方式“链接”express.js到所述控制器?定制中间件
是一种核心选项。这可以通过使用策略来实现。使用策略听上去像是一种骇人听闻的行为,因为它的名字叫“策略”,所有的例子都集中在访问控制等方面。它可能是目前最好的地方,但天哪,真的吗?政策在这里会很好;只需在策略中的res.locals
中设置所需的数据,它将对每个视图都可用。在策略中设置类似这样的内容的问题是,策略不会针对404这样的错误页面运行,这些页面仍然希望使用默认布局(并且可能应该使用默认布局)。最终会出现错误和/或不一致。