如何使用Meteor Spacebars模板动态呈现HTML?

时间:2014-05-01 19:36:04

标签: templates meteor meteor-blaze spacebars meteor-helper

因此,我要说我在我的数据库中存储了<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+版本的支持。关于如何让它发挥作用的任何想法都非常感谢。

6 个答案:

答案 0 :(得分:9)

在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

中的UI动态进行渲染

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

答案 1 :(得分:7)

您实际上可以使用空格键编译器自己将字符串编译为模板。您只需使用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);

答案 2 :(得分:3)

关注@ 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');

将模板名称保存在Session变量中。下一点将解释这一点的重要性。

3)编写一个辅助函数来返回模板名称。我使用Session变量来做到这一点。如果要在单击事件上添加动态内容或者已经呈现父模板,这一点很重要。否则,您将永远不会看到动态模板被渲染。

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

4)写这是父模板的渲染方法。这是为了重置Session变量。

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

这对我有用。希望它可以帮到某人。

答案 3 :(得分:1)

如果您需要动态编译 复杂模板,我建议Kelly回答。

否则,您有两种选择:

  1. 创建每个模板变体,然后动态选择正确的模板:

    例如,创建模板

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

    然后用

    动态包含它们
    {{> Template.dynamic template=templateName}}
    

    templateName是帮助者返回"age""name"

  2. 的地方
  3. 如果您的模板很简单,只需自己执行替换即可。您可以使用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)
          );
      }
    

答案 4 :(得分:1)

幸运的是,整个问题的解决方案以及类似的任何其他问题都以Blaze package的形式提供给Meteor API,这是使反应模板成为可能的核心Meteor包。如果您查看链接文档,Blaze包提供了一长串函数列表,这些函数允许以编程方式创建,呈现和删除被动和非被动内容的各种解决方案。

为了解决上述问题,您需要执行以下操作:

首先,预测需要为应用程序动态呈现的不同HTML块。在这种情况下,这些块将是<div>{{name}}</div><div>{{age}}</div>,但它们实际上可以是任何有效的HTML(尽管它还不是公共API的一部分,未来开发人员将有更多的选择用于以更动态的方式定义此内容,如文档中提到的here。您可以将它们放入小模板定义中,如下所示:

<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.WithBlaze.render和{{3 (虽然你可以改变以下逻辑并利用Blaze.remove函数;它完全取决于你个人对你如何定义逻辑的偏好 - 我只是为了下面提供一个可能的解决方案解释)。

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()回调函数中的渲染视图,并确保它真正被破坏。

答案 5 :(得分:1)

一种非常简单的方法是在onRendered事件中包含对全局Blaze对象的调用。

Blaze.renderWithData(Template[template_name], data ,document.getElementById(template_id))