Не удается отобразить шаблон EJS на клиенте

Я пишу приложение на экспресс, и я использую ejs в качестве движка представления / шаблона.

На пути /artistsЯ предоставляю вид artists.ejs который имеет обложки художников. При нажатии на обложку я хочу, чтобы вызов AJAX извлек соответствующие данные, поместил их в мой шаблон / представление для исполнителя. artist.ejs и отобразить этот шаблон в моем HTML под обложкой.

Я видел этот связанный вопрос, но он не решил мой вариант использования.

Все кажется ясным, но я не могу отобразить данные с помощью шаблона. Я хотел бы скомпилировать шаблон на стороне сервера, отправить его готовому к использованию клиенту, а затем заполнить его при необходимости данными, полученными из вызова 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);
}

Но когда я звоню, я получаю:

Uncaught ReferenceError: fn не определен

Когда я вызываю шаблон, fn, Я получил:

Uncaught ReferenceError: opts не определен.

Является ли функция fn жестко? Я прочитал документацию по EJS и Jade, но по моей проблеме было мало соответствующей информации.

Возможно, мне также нужен шаблон на стороне клиента?

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

Таким образом, я отправляю все свои шаблоны при первой загрузке страницы, а затем отображаю запрошенную страницу на стороне клиента. В соответствии с тем, что я прочитал, интерес состоит в том, что вы отправляете объект JSON (ваши данные) только через вызовы AJAX, а не всю страницу, что делает ваш запрос светлым. Только первая загрузка тяжелая со всеми вашими шаблонами.

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

Но это тоже не сработает.

У вас есть идея, что мне здесь не хватает? И наконец, вы согласны с тем, что компиляция их на стороне сервера перед использованием функций лучше с точки зрения вычислений, чем рендеринг каждого шаблона на стороне клиента?

Спасибо за помощь, и надеюсь, что это поможет кому-либо еще!

Вам нужно использовать client опция на стороне сервера при компиляции для клиента. Из документов:

  • client когда true, компилирует функцию, которую можно отобразить в браузере, не загружая EJS Runtime

https://github.com/mde/ejs

Ваш фрагмент кода на стороне сервера должен быть:

// 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});
});
Другие вопросы по тегам