【问题标题】:Dynamically loading templates in Meteor.js在 Meteor.js 中动态加载模板
【发布时间】:2012-10-09 17:55:29
【问题描述】:

我希望能够在不明确指定模板的情况下动态加载模板。

举个例子:

<template name="foo">
</template>

'foo' 是模板,我希望能够通过调用一些方法来动态加载它:

Meteor.render(Meteor.loadTemplate('foo'));

这可能吗?

【问题讨论】:

    标签: javascript meteor


    【解决方案1】:

    以下是从 Meteor 0.9.4 - 1.0 开始动态渲染模板的方法。在撰写本文时,所有其他答案都已过时。

    假设您正在编辑一堆记录,或者创建一个新记录,并且想要根据一些 Session 变量呈现 update 模板或 new 模板。

    有两种方法可以做到这一点:

    1) 这是 Meteor 0.9.4 或更新版本官方推荐的方法 - 它使用Template.dynamic

    <template name="records">
      {{> Template.dynamic template=whichOne}}
    </template>
    
    <template name="recordUpdate">
      ...
    </template>
    
    <template name="recordNew">
      ...
    </template>
    
    Template.records.helpers({
      whichOne: function () {
        return Session.get('edit') ? 'recordUpdate' : 'recordNew'
        // note that we return a string - per http://docs.meteor.com/#template_dynamic
      }
    });
    

    2) 这适用于各种 Meteor 版本,但不推荐正式使用,因为不清楚模板是动态选择的:

    <template name="records">
      {{> whichOne}}
    </template>
    
    {{! Note how "whichOne" is indistinguishable from a constant template name... }}
    {{  ...like "recordUpdate" or "recordNew" below. }}
    
    <template name="recordUpdate">
      ...
    </template>
    
    <template name="recordNew">
      ...
    </template>
    
    Template.records.helpers({
      whichOne: function () {
        return Session.get('edit') ? Template.recordUpdate : Template.recordNew
        // note that we return a Template object, not a string
      }
    });
    

    要将数据上下文传递给模板,请使用:

    {{> Template.dynamic template=whichOne data=myData}}
    

    【讨论】:

    • 这是现在最流行的答案,但我建议展示如何选择性地将数据传递到范围。 {{> Template.dynamic template=whichOne 数据=myData}}
    • 优秀 - +1 因为你花时间写了随着 Meteor 的“版本化”发展而用当前信息更新我们的事实。我发现自己使用#1 方法。收到调试报告后我很满意,因为错误是我所期望的,并且与我看到的成千上万的调试报告相比并没有不成比例。但是,方法 #2 返回的报告不太详细,并且仍然存在一些错误 - 可能是因为(我不确定,但怀疑)当涉及“中间处理”时,它在过程之间“过于动态”。感谢您提供最新信息。
    • @Turbo @DanDascalescu :: 关于可选传递数据的行,data=myData sn-p: 是key=value吗?
    • @Faron:这是整个数据上下文。见docs.meteor.com/#/full/template_dynamic
    • @Faron 参数名称具体为数据,其值将成为模板的 this 上下文。 myData 是一个可在所选模板中访问的对象。
    【解决方案2】:

    Meteor 0.8.x 旧版

    使用Joc's 回答作为指导, 我使用http://docs.meteor.com/#template_call 实现了类似的效果,但使用了帮助器,正如文档所建议的那样:

    当在模板助手、Meteor.render 的主体或生成响应式 HTML 的其他设置中调用时,生成的 HTML 会被注释,以便它呈现为响应式 DOM 元素

    我的 client.js 看起来有点像这样:

    Template.myPageTemplate.helpers({
      dynamicTemplate: function() {
        // conditional logic can be added here to determine which template to render
        return Template.myDynamicTemplate();
      }
    });
    

    我的 html 看起来像这样:

    <template name="myPageTemplate">
      <h1>My Template</h1>
      {{{dynamicTemplate}}}
    </template>
    
    <template name="myDynamicTemplate">
      <h1>My Dynamic Template</h1>
    </template>
    

    【讨论】:

    【解决方案3】:

    Meteor 0.9.x 新 API

    Dan Dascalescu 指出 Meteor 现在有内置的动态模板!这很好,因为您不需要像以前版本中那样包含额外的代码。

    {{> Template.dynamic template=template [data=data] }}
    

    对于 Meteor 0.8.x 旧版

    动态模板没有数据:Boris Kotov 更新的 Blaze (0.8.0) 答案在正确的轨道上(取自最新文档),但它对我来说不起作用。我得到了以下工作:

    {{> dynamicTemplate name=myDynName}}
    
    <template name="dynamicTemplate">
        {{#with chooseTemplate name}}
            {{> template}}
       {{/with}}
    </template>
    
    Template.dynamicTemplate.chooseTemplate = function (name) {
        return { template: Template[name] };
    };
    

    我希望有一个更简单的解决方案,但我需要将模板包装在 JSON 中,如图所示。也许这会帮助其他人继续前进。

    Dynamic Template With 数据:如果您拥有并且希望数据是动态的,请务必创建一个可以做出反应的辅助方法。请务必在某处执行 Session.set() 以查看效果。

    // Inside "myContainingTemplate"
    {{> dynamicTemplateWithData name=myDynName data=myDataHelper}}
    
    <template name="dynamicTemplateWithData">
        {{#with chooseTemplate name}}
            {{#with ../data}}
                {{> ..}}
            {{/with}}
        {{/with}}
    </template>
    
    Template.dynamicTemplateWithData.chooseTemplate = function (name) {
        return Template[name];
    };
    
    Template.myContainingTemplate.helpers({
        myDataHelper: function () {
            Session.get('myReactiveKey');
        }
    });
    

    【讨论】:

    【解决方案4】:

    来自https://github.com/meteor/meteor/wiki/Using-Blaze

    {{> post}}
    
    Template.foo.helpers({
      post: function () {
        return Template[this.postName];
      }
    });
    

    模板包含现在在帮助器和数据的命名空间中搜索模板对象,因此可以轻松地以编程方式选择要使用的模板。这是一个强大的功能,并且允许将一个模板分配为另一个模板的帮助器这样的模式,以便可以覆盖它。

    【讨论】:

    • 谢谢!我已经删除了不推荐使用的代码。 (这仍然不是推荐的解决方案。)
    【解决方案5】:

    这将处理有数据和没有数据的动态模板: (需要 Blaze/Meteor 0.8)

    {{> dynamicTemplate name=templateName}}
    
    <template name="dynamicTemplate">
        {{#with chooseTemplate name }}
            {{#if ../data}}
                {{#with ../data }}
                    {{> .. }}
                {{/with}}
            {{else}}
                {{> this}}
            {{/if}}
        {{/with}}
    <template name="dynamicTemplate">
    

    模板javascript:

    Template.dynamicTemplate.chooseTemplate = function (name) {
        return Template[name];
    };
    

    【讨论】:

    【解决方案6】:

    对我来说,最简单的方法就是创建一个函数 get_dynamic_template,如下所示:

    var a= get_dynamic_template(template_name,data);
    

    它返回可以呈现为普通变量的内容 {{a}}

    这个函数的代码很简单:

    var get_dynamic_template = function(template_name,data)
    {
    
          return function(){
            return new Handlebars.SafeString(
              UI.toHTML(
                   Template[template_name].extend({data: function () { return data; }}))
              );
          };
    
    }
    

    【讨论】:

      【解决方案7】:

      火焰更新:

      https://github.com/meteor/meteor/wiki/Using-Blaze#templatefoo-is-not-a-function-and-does-not-return-a-string

      使用给定的数据上下文动态呈现模板

      旧:

      {{dynamicTemplate name="templateName" data=dataContext}}
      
      Template.foo.dynamicTemplate = function (opts) {
        return Template[opts.name](opts.data);
      };
      

      新:(值得注意的是,在 Blaze 中,包含或块助手的关键字参数被捆绑到成为新数据上下文的单个对象中)

      {{> dynamicTemplate name="templateName" data=dataContext}}
      
      <template name="dynamicTemplate">
        {{#with chooseTemplate name}}
          {{#with ../data}}  {{! original 'data' argument to DynamicTemplate}}
            {{> ..}}         {{! return value from chooseTemplate(name) }}
          {{/with}}
        {{/with}}
      </template>
      
      Template.dynamicTemplate.chooseTemplate = function (name) {
        return Template[name];
      }
      

      顺便说一句,我并没有真正玩过它,但这是我从新的 blaze 文档中得到的。所以我认为这应该是这样做的方式;)

      【讨论】:

      • 上下文是什么意思?? id 你mena name="templateNAME"吗?
      • 是的,正确的。在这种情况下,id 是模板的标识符或模板的名称。上下文变量是您放入模板的内容。希望对您有所帮助。
      • 你如何或在哪里设置 id 和 context?
      • 克里斯蒂安,我将我的回答更新到了新的 0.8.0 版本。
      • 这已过时 - 请参阅 my answergithub.com/meteor/meteor/issues/2836 关于直接分配给 Template.foo 的信息。
      【解决方案8】:

      根据 hillmark 的回答,这是最简单的:

      Template.main.template = function() {
        if (some_condition) {
          return Template.A();
        } else {
          return Template.B();
        }
      };
      

      带有对应的.html

      <body>
          {{> main}}
      </body>
      
      <template name="main">
          {{{template}}}
      </template>
      
      <template name="A">
          <h1>Template A</h1>
      </template>
      
      <template name="B">
          <h1>Template B</h1>
      </template>
      

      编辑 在 Meteor 0.8.0 中不起作用

      【讨论】:

      【解决方案9】:

      您已经找到 Meteor.render,但您缺少的是模板加载。 在文档中提到您可以调用 Template.foo() 来返回模板的 HTML。

      http://docs.meteor.com/#template_call

      将它们放在一起,您可以访问模板 foo 或任何其他使用括号访问的模板,因此:

      var templateName = "foo";
      var fragment = Meteor.render( function() {
          return Template[ templateName ](); // this calls the template and returns the HTML.
      });
      

      那么fragment就是你的响应式fragment,这样你的模板就可以继续接收实时更新。您的片段现在需要放置在网页中(我使用 jQuery,所以这个示例也是如此):

      $("#htmlnode").html( fragment );
      

      $("#htmlnode") 只是 DOM 中的一个节点,您希望在其中呈现模板。现在,您的网页中已经有了渲染的内容。

      【讨论】:

      • 这对我有用,只是做了一些小的改动。因为我已经用 div 标签包围了模板中的元素,所以使用上面的代码呈现了一个未定义的片段。调用 Meteor.render( Template[ templateName ] ) 解决了这个问题。
      • 以防万一有人对代码有问题,您可能需要先使用“if (Template[templateName])”检查模板是否可访问,然后再调用它。
      • 非常正确,戴夫。如果模板不存在,我倾向于向控制台打印一条消息,以便我立即知道我是否使用了错误的名称等。
      • 我希望这适用于返回 HTML 字符串,而不是 documentFragment,这样您就可以让 Meteor 的 Spark 呈现模板,即在另一个模板中。有谁知道该怎么做?返回文档片段作为模板助手不起作用,并且返回在提供给 render() 的函数中生成的字符串。它有所有地标、标签的东西。
      • 这个答案和 cmets 已被 Meteor 0.9.4 淘汰 - 请参阅 my answergithub.com/meteor/meteor/issues/2836 关于直接分配给 Template.foo 的信息。
      【解决方案10】:

      我就是这么干的,不需要jQuery:

      已编辑

      Template.mainContent.showContentFromRouter = function() {
          return Template[Meteor.Router.page()]();
      };
      

      在这种情况下,我使用 Meteor 路由器,并返回我选择的任何模板(从路由器),但你可以这样做:

      Template.mainContent.showDynamicContent = function() {
          return Template['someTemplateYouveDefined']();
      };
      

      【讨论】:

      • 当我尝试这个时,标记在页面上显示为一个字符串。你如何解决这个问题?
      • 您在模板中的 {{showContentFromRouter}} 周围添加了一个额外的 {}。像这样:{{{showContentFromRouter}}}。此 HTML 转义字符串。 @Samo
      • 这个方案的问题是模板在内存中一遍遍的生成,只要调用了showDynamicContent函数。有没有办法从内存中删除模板?我通过渲染 1000 多个子模板并来回删除它们来测试这一点
      • @frozeman,我不太明白你的意思。你能用我的解决方案测试它吗? - >#2答案。或者告诉使用,如何测试它=)
      • 这是非常过时的 - 请参阅 my answergithub.com/meteor/meteor/issues/2836 关于直接分配给 Template.foo
      猜你喜欢
      • 1970-01-01
      • 2018-11-22
      • 2015-01-15
      • 2012-09-03
      • 2017-04-08
      • 1970-01-01
      • 2016-03-29
      • 2011-05-03
      • 1970-01-01
      相关资源
      最近更新 更多