Как я могу динамически отображать HTML с помощью шаблонов Meteor Spacebars?

Допустим, я храню <div>{{name}}</div> и <div>{{age}}</div> в своей базе данных. Затем я хочу взять первую строку HTML и отобразить ее в шаблоне — {{> template1}}, который просто отображает первую строку с рулем {{name}} в ней. Затем я хочу предоставить эти недавно сгенерированные данные шаблона/html, чтобы он мог заполнить руль фактическим name из базы данных, чтобы мы получили <div>John</div>. я пытался сделать

<template name="firstTemplate">
    {{#with dataGetter}}
        {{> template1}}
    {{/with}}
</template>

Где template1 определяется как

<template name="template1">
    {{{templateInfo}}}
</template>

А templateInfo — это хелпер, который возвращает из базы данных вышеупомянутую html-строку с рулем.

dataGetter как раз это (просто пример, я работаю с коллекциями с разными именами)

Template.firstTemplate.dataGetter = function() {
    return Users.findOne({_id: Session.get("userID")});
}

Я не могу заполнить {{name}}. Я пробовал это несколькими разными способами, но похоже, что Meteor не понимает, что рули в строке должны оцениваться с данными. У меня 0.7.0, так что нет Blaze, я не могу обновиться в данный момент из-за других пакетов, которые я использую, у них просто пока нет поддержки версии 0.8+. Любые идеи о том, как я могу заставить это работать, очень ценятся.


person Danail Gabenski    schedule 01.05.2014    source источник


Ответы (6)


Если вам нужно динамически компилировать сложные шаблоны, я бы предложил ответ Келли.

В противном случае у вас есть два варианта:

  1. Создайте каждый вариант шаблона, а затем динамически выберите нужный шаблон:

    например, создать свои шаблоны

    <template name="displayName">{{name}}</template>
    <template name="displayAge">{{age}}</template>
    

    А затем включить их динамически с помощью

    {{> Template.dynamic template=templateName}}
    

    Где templateName — помощник, который возвращает "age" или "name"

  2. Если ваши шаблоны простые, просто выполните замену самостоятельно. Вы можете использовать Spacebars.SafeString для возврата HTML.

    function simpleTemplate(template, values){
          return template.replace(/{{\w+}}/g, function(sub) {
              var p = sub.substr(2,sub.length-4);
              if(values[p] != null) { return _.escape(values[p]); }
              else { return ""; }
          })
    }
    Template.template1.helpers({
      templateInfo: function(){
          // In this context this/self refers to the "user" data
          var templateText = getTemplateString();
          return Spacebars.SafeString(
              simpleTemplate(templateText, this)
          );
      }
    
person nathan-m    schedule 01.05.2014
comment
Да, вчера я выбрал второй вариант, надеюсь, Blaze и все, что за ним последует, даст нам возможность компилировать html в руль на лету. Все еще бесит меня, я должен переделать руль самостоятельно, вздох. - person Danail Gabenski; 02.05.2014
comment
JSYK eval используется внутри пакета шаблонов для создания шаблона. Строка, которую компилятор пробелов проанализирует ваши строки и экранирует их правильно, так же, как и ваши шаблоны. - person Kelly Copley; 08.05.2014
comment
Что касается тегов, вы можете проанализировать любые теги ‹script›. - person Kelly Copley; 08.05.2014

В 1.0 ни один из описанных выше способов не работает. Я заставил это работать с функцией, определенной ниже в клиентском коде. Ключ был в том, чтобы передать параметры {isTemplate: true} в функцию компиляции.

var compileTemplate = function(name, html_text) {
  try {
    var compiled = SpacebarsCompiler.compile(html_text, { isTemplate:true });
      var renderer = eval(compiled);
      console.log('redered:',renderer);
      //Template[name] = new Template(name,renderer);
      UI.Template.__define__(name, renderer);
  } catch (err){
    console.log('Error compiling template:' + html_text);
    console.log(err.message);
  }
};

Вы можете позвонить с чем-то вроде этого на клиенте:

compileTemplate('faceplate', '<span>Hello!!!!!!{{_id}}</span>');

Это будет отображаться с динамическим пользовательским интерфейсом в вашем html.

{{> Template.dynamic template='faceplate'}}

person user3354036    schedule 14.11.2014
comment
Обязательно добавьте пакет spacebars-compiler (meteor add spacebars-compiler), чтобы вы могли использовать SpacebarsCompiler - person Alban Lecocq; 19.02.2015
comment
Я получаю сообщение 'reded:function anonymous()' в консоли, НО {{›UI.dynamic template='faceplate'}} ничего не делает в моем случае. Я использую Метеор 1.1.0.2 - person Rushikesh Gomekar; 24.07.2015
comment
Как визуализировать дочерний шаблон лицевой панели, т. е. который обычно {{› дочерний }} внутри лицевой панели, но не визуализировать с динамическим добавлением {{› Template.dynamic template = 'faceplate'}} - person Abdul Hameed; 02.09.2016

На самом деле вы можете скомпилировать строки в шаблоны самостоятельно, используя компилятор пробелов. Вам просто нужно использовать meteor add spacebars-compiler, чтобы добавить его в свой проект.

В проектах с использованием 0.8.x

var compiled = Spacebars.compile("<div>{{name}}</div> and <div>{{age}}</div>");
var rendered = eval(compiled);

Template["dynamicTemplate"] = UI.Component.extend({
  kind: "dynamicTemplate",
  render: rendered
});

В проектах с использованием 0.9.x

var compiled = SpacebarsCompiler.compile("<div>{{name}}</div> and <div>{{age}}</div>");
var renderer = eval(compiled);

Template["dynamicTemplate"] = Template.__create__("Template.dynamicTemplate", rendered);
person Kelly Copley    schedule 02.05.2014
comment
Ха, это еще лучшее решение, я посмотрю на него. Не уверен, что у меня есть класс пользовательского интерфейса, доступный в 0.7.0. - person Danail Gabenski; 03.05.2014
comment
Такой упаковки вроде нет - ни в метеоре, ни в метеорите. Я думаю, это метеорит после 0.7.0. - person Danail Gabenski; 06.05.2014
comment
Поскольку пробелы являются частью пользовательского интерфейса Meteor, я думаю, вам понадобится Meteor › 0.8.0 - person Kelly Copley; 07.05.2014
comment
Плохо, я думал, что пробелы - это просто название Meteor для рулей, независимо от версии Meteor. Я предполагаю, что они просто переименовали их для 0.8.x+. Хотя все еще на 0.7.0. - person Danail Gabenski; 29.05.2014

После ответа @ user3354036:

var compileTemplate = function(name, html_text) {
  try {
    var compiled = SpacebarsCompiler.compile(html_text, { isTemplate:true }),
        renderer = eval(compiled);

    console.log('redered:',renderer);
    //Template[name] = new Template(name,renderer);
    UI.Template.__define__(name, renderer);
  } catch (err) {
    console.log('Error compiling template:' + html_text);
    console.log(err.message);
  }
};

1) Добавьте это в свой HTML

 {{> Template.dynamic template=template}}

2) Вызвать метод compileTemplate.

compileTemplate('faceplate', '<span>Hello!!!!!!{{_id}}</span>');
Session.set('templateName','faceplate');

Сохраните имя шаблона в переменной сеанса. Важность этого объясняется в следующем пункте.

3) Напишите вспомогательную функцию для возврата имени шаблона. Для этого я использовал переменную сеанса. Это важно, если вы добавляете динамическое содержимое в событие щелчка или если родительский шаблон уже отрендерен. В противном случае вы никогда не увидите визуализацию динамического шаблона.

'template' : function() {
  return Session.get('templateName');
}

4) Напишите, что это визуализированный метод родительского шаблона. Это необходимо для сброса переменной сеанса.

Session.set('templateName','');

Это сработало для меня. Надеюсь, это поможет кому-то.

person Rushikesh Gomekar    schedule 25.02.2016
comment
Здорово! очень признателен, спас мой день :) - person Abdul Hameed; 06.06.2016
comment
после рендеринга мои предыдущие вспомогательные функции перестают работать, сталкивались ли вы с этим - person Abdul Hameed; 09.06.2016
comment
Не забудьте запустить meteor add spacebars-compiler, чтобы иметь возможность использовать SpacebarsCompiler. - person Harry Adel; 08.01.2020

К счастью, решение всей этой проблемы и любых других подобных проблем было предоставлено Meteor API в виде Пакет Blaze, который является основным пакетом Meteor, делающим возможными реактивные шаблоны. Если вы посмотрите на связанную документацию, пакет Blaze предоставляет длинный список функций, которые позволяют использовать широкий спектр решений для программного создания, рендеринга и удаления как реактивного, так и нереактивного контента.

Для того, чтобы решить описанную выше проблему, вам необходимо сделать следующее:

Во-первых, предусмотрите различные фрагменты HTML, которые должны быть динамически отображены для приложения. В этом случае эти фрагменты будут <div>{{name}}</div> и <div>{{age}}</div>, но на самом деле они могут быть любым допустимым HTML (хотя он еще не является частью общедоступного API, в будущем у разработчиков будет больше возможностей для определения этого содержимого в более динамичном формате). способом, как указано здесь в документации). Вы бы поместили их в небольшие определения шаблонов, например:

<template name="nameDiv">
    <div>{{name}}</div>
</template>

а также

<template name="ageDiv">
    <div>{{age}}</div>
</template>

Во-вторых, необходимо изменить определение шаблона firstTemplate, чтобы оно содержало HTML-узел, на который можно ссылаться программно, например так:

<template name="firstTemplate">
    <div></div>
</template>

Затем вам потребуется определить логику для вашего шаблона firstTemplate, которая использует преимущества некоторых функций, предоставляемых пакетом Blaze, а именно Blaze.With, Blaze.render и Blaze.remove (хотя вы можете изменить следующую логику и воспользоваться преимуществами Blaze.renderWithData; все зависит от ваших личных предпочтений относительно того, как вы хотите определить свою логику - я предоставьте только одно возможное решение ниже для объяснения).

Template.firstTemplate.onRendered(function() {
    var dataContext = Template.currentData();
    var unrenderedView = Blaze.With(dataContext, function() {
        // Define some logic to determine if name/age template should be rendered
        // Return either Template.nameDiv or Template.ageDiv
    });
    var currentTemplate = Template.instance();
    var renderedView = Blaze.render(unrenderedView, currentTemplate.firstNode);

    currentTemplate.renderedView = renderedView;
});

Template.firstTemplate.onDestroyed(function() {
    var renderedView = Template.instance().renderedView;
    Blaze.remove(renderedView);
});

То, что мы делаем здесь, в функции onRendered для вашего шаблона firstTemplate, динамически определяем, какие фрагменты данных мы хотим отобразить на странице (имя или возраст в вашем случае), и используем функцию Blaze.With() для создания необработанного представления. этого шаблона, используя контекст данных шаблона firstTemplate. Затем мы выбираем узел элемента шаблона firstTemplate, в котором мы хотим, чтобы динамически сгенерированный контент содержался, и передаем оба объекта в функцию Meteor.render(), которая отображает неотображенное представление на странице с указанным узлом элемента в качестве родительского узла отображаемого содержимого. .

Если вы прочтете подробности о функции Blaze.render(), вы увидите, что это отображаемое содержимое будет оставаться реактивным до тех пор, пока отображаемое представление не будет удалено с помощью функции Blaze.remove() или указанный родительский узел не будет удален из DOM. В моем примере выше я беру ссылку на визуализированное представление, которое я получил от вызова Blaze.render(), и сохраняю его непосредственно в объекте шаблона. Я делаю это для того, чтобы при уничтожении самого шаблона я мог вручную удалить отрендеренное представление в функции обратного вызова onDestroyed() и быть уверенным, что оно действительно уничтожено.

person Keith Dawson    schedule 18.08.2015

Очень простой способ — включить в событие onRendered вызов глобального объекта Blaze.

Blaze.renderWithData(Template[template_name], data ,document.getElementById(template_id))
person Adrian Badarau    schedule 26.01.2016