无法在客户端渲染EJS模板

4
我正在使用express编写一个应用程序,并使用ejs作为视图/模板引擎。
在路径/artists处,我正在呈现视图artists.ejs,其中包含艺术家封面。单击封面时,我想要进行AJAX调用以检索相应的数据,将其放置在我的艺术家artist.ejs的模板/视图中,并在我的HTML下方显示此模板。
我已经看到了this相关问题,但它没有解决我的用例。
一切似乎很清楚,但我无法使用模板呈现数据。我想在服务器端编译模板,将其准备好发送给客户端,然后在需要时使用从AJAX调用接收到的数据填充它。
我所做的:
在调用/artists时,在服务器端使用ejs.compile(str, opt)进行编译:
router.get('/artists', function(req, res) {

// Compile artist template
fs.readFile('views/artist.ejs', "utf-8", function(err, template) { // Convert template file to string
    artist_template = ejs.compile(template); // Compile template

    res.render('artists.ejs', {template: artist_template}); // render page with compiled template
});

我负责将文件转换为字符串,因为ejs编译器只能使用字符串(与Jade .compileFile相比)

然后在客户端,我获取该函数:

<script>
    var template = <%= template %>
</script>

然后在另一个脚本中,我通过AJAX调用检索数据:

$.get('/artists/'+artist_name, function(data) {
    var html = template({artist: data});
    $('#artist-page').html(html);
}

但是当我调用时,我收到以下信息:

未捕获的引用错误:fn未定义

当我调用模板 fn 时,我收到以下信息:

未捕获的引用错误:opts未定义。

函数 fn 是否硬编码? 我已阅读EJS和Jade文档,但与我的问题相关的信息很少。
我可能需要在客户端也使用模板吗?
2个回答

2

我最终找到了解决问题的方法,通过你的回答,我明白可以有两种不同的方法:

1)我采取的方法是:将模板读取并保存为字符串,然后使用ejs运行时脚本在客户端呈现。

// In controller.js    
var templates = {};
templates.template1 = fs.readFileSync(filePath1, 'utf-8'); // Read template as a string
templates.template2 = fs.readFileSync(filePath2, 'utf-8');     
...
res.render('app.ejs', {templates: templates}); // Send templates in view

// In view app.ejs
<script type="text/javascript">
   var templates = <%- JSON.stringify(templates) %>; // Get templates object (object of strings) 
</script>
<script type="text/javascript" src="/JS/ejs.min.js"></script> <!-- Load ejs RunTime -->

// In site.js - javascript client/public file
$.get('/artists', function(data) {
     var html = ejs.render(templates.template1, data); // Render ejs client side with EJS script (template1 corresponds to the artists template)
     $('#artists-wrapper').html(html); // Sets HTML
});

因此,我在首次页面加载时发送所有模板,然后在客户端渲染请求的页面。根据我所读到的,优点是通过 AJAX 调用仅发送 JSON 对象(您的数据),而不是整个页面,使您的请求变得轻便。只有第一次加载需要发送包含所有模板的内容。
2)根据@RyanZim的回答,我想做的是:将模板服务器端编译成函数,发送它们,然后在客户端调用它们:template(data)。如果我理解正确,这种情况下不需要 EJS 客户端库,我的模板也不再是字符串,而是函数。
// In controller.js    
var templates = {};
templates.template1 = ejs.compile(fs.readFileSync(filePath1, 'utf-8'), {client: true}); // Get template as a function
templates.template2 = ejs.compile(fs.readFileSync(filePath2, 'utf-8'), {client: true});     
...
res.render('app.ejs', {templates: templates}); // Send templates in view

然而,我无法在视图中看到它们:
<script type="text/javascript">
   var templates = <%- JSON.stringify(templates) %>; // Get templates object (object of functions) 
</script>   

不起作用。它们是在我发送它们之前在服务器上执行的函数,但我不知道如何恢复它们。你有想法吗?

我尝试了一种解决方法,通过在发送之前将它们转换为字符串:

templates.template1 = templates.template1.toString();

将它们发送到客户端,然后在函数中转换回来。
var template = new Function(templates.template1);
$.get('/artists', function(data) {
     var html = template(data);
     $('#artists-wrapper').html(html); // Sets HTML
});

但这也不行。

你有没有想到我漏了什么?最后,你认为在使用函数之前在服务器端编译它们比在客户端渲染每个模板更好计算吗?

感谢帮助,并希望这能帮助其他人!


首先,我发现你的问题非常有用,因为我正在尝试做同样的事情。你最终解决了这个问题吗? - Richlewis
@Richlewis,嘿,谢谢你的评论。是的,我按照第1点所描述的方式将模板存储为字符串,然后使用EJS客户端.js进行渲染。你试过吗? - M. Arb
我现在已经成功编译了我的HTML服务器端,但进入我的视图是下一步。https://stackoverflow.com/questions/50378874/render-ejs-node-js - Richlewis

1
在编译客户端时,您需要在服务器端使用client选项。来自文档的说明:
  • client 当为true时,编译一个函数,可以在浏览器中呈现而无需加载EJS运行时。

https://github.com/mde/ejs#options

您的服务器端代码片段应该是:

// Compile artist template
fs.readFile('views/artist.ejs', "utf-8", function(err, template) {
  artist_template = ejs.compile(template, {client: true}); // Use client option

  res.render('artists.ejs', {template: artist_template});
});

嘿,Ryan,谢谢你的回答。我按照下面我的回答中解释的方法进行了解决,它运行得很好,但我也想尝试一下这种技术,即在服务器端编译模板,然后在客户端运行它,但是无法使其运行!你能帮我解决这个问题吗?谢谢! - M. Arb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接