无法在客户端上呈现EJS模板

时间:2016-10-13 14:28:10

标签: javascript node.js templates client-side ejs

我在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
});

我负责将文件转换为String,因为ejs编译器仅适用于String(与Jade .compileFile相比)

然后在客户端,我抓住了这个功能:

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

然后在另一个脚本上,我使用AJAX调用检索数据:

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

但是当我拨打电话时,我收到了:

  

未捕获的ReferenceError:未定义fn

当我调用模板fn时,我会收到:

  

未捕获的ReferenceError:未定义opts。

函数fn是否经过硬编码?我已经阅读了EJS和Jade文档,但关于我的问题几乎没有相关信息。

我是否也需要客户端的模板?

2 个答案:

答案 0 :(得分:2)

我最终找到了一个问题的解决方法,我理解你的答案,你可以用两种不同的方式进行:

1)我做了什么:读取并将模板保存为字符串,然后使用ejs Runtime脚本将其呈现在客户端。

// 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>   

无效。它们是我发送之前在服务器上的功能,但我不知道如何恢复它们。你有什么想法吗?

我尝试了一种解决方法,在发送之前将它们更改为String:

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
});

但这也行不通。

你知道我在这里缺少什么吗? 最后,您是否同意在使用函数之前编译服务器端在计算方面比在呈现每个模板客户端方面更好?

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

答案 1 :(得分:0)

在为客户端编译时,需要在服务器端使用client选项。来自文档:

  
      
  • clienttrue时,编译可以渲染的函数   在浏览器中,无需加载EJS Runtime
  •   

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});
});