Не удается отобразить шаблон 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
Ваш фрагмент кода на стороне сервера должен быть:
// 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});
});