将Handlebars模板作为变量传递给Handlebars模板

时间:2014-03-24 07:33:56

标签: ember.js handlebars.js

我遇到需要渲染用户创建的Handlebars模板的情况。我已经能够破解一个解决方案:使用视图将用户生成的模板+上下文编译成HTML,然后将结果字符串提供给“最终”模板。

我希望能够将模板作为变量暴露给“最终”模板,并让最终模板对其进行评估,就好像它是实际的HBS代码一样;但是如果我使用三个大括号{{{,那么把手变量(当然)会被转义。

还有其他办法吗?也许是一个助手,首先用一些上下文编译变量,然后输出字符串?这里唯一的问题是Ember.Handlebars与Ember合作;我只需要最终的,未绑定的HTML。

2 个答案:

答案 0 :(得分:4)

一种可能的方法是使用专用于呈现用户定义模板的view。然后通过设置其template变量并重新渲染它,模板可以动态更改。

实施例,

http://emberjs.jsbin.com/yexizoyi/1/edit

<强> HBS

<script type="text/x-handlebars">
    <h2> Welcome to Ember.js</h2>

    {{outlet}}
  </script>

  <script type="text/x-handlebars" data-template-name="test">
    this is the test,

    {{view view.userTemplate}}

    <button {{action "changeTemplate" 1 target="view"}}>change to Template 1</button>
    <button {{action "changeTemplate" 2 target="view"}}>change to Template 2</button>
  </script>

<强> JS

App.Router.map(function() {
  this.route("test");
});

App.IndexRoute = Ember.Route.extend({
  beforeModel: function() {
    this.transitionTo("test");
  }
});

App.UserTemplateView = Ember.View.extend({
  template:Ember.Handlebars.compile("initial default template <b>{{view.parentView.parentVar}}</b>")
});

App.TestView = Ember.View.extend({
  parentVar:"this is a parent variable",
  userTemplate:App.UserTemplateView.create(),
  actions:{
    changeTemplate:function(templateId){
      if(templateId===1){
        this.get("userTemplate").set("template",Ember.Handlebars.compile("this is template 1 <b>{{view.parentView.parentVar}}</b>"));
        this.get("userTemplate").rerender();
      }else{
        this.get("userTemplate").set("template",Ember.Handlebars.compile("this is template 2 <b>{{view.parentView.parentVar}}</b>"));
        this.get("userTemplate").rerender();
      }
    }
  }
});

也可以使用ContainerViewhttp://emberjs.com/guides/views/manually-managing-view-hierarchy/

来实现

例如, http://emberjs.jsbin.com/luzufixi/1/edit

编辑 - 使用助手补充评论和Sam Selikoff的良好解决方案

这是使用前一个概念的一个更粗略的例子,以及路由器的模型和由{{view}}对象支持的View助手,即PreviewTemplateView

http://emberjs.jsbin.com/tonapaqi/1/edit

http://emberjs.jsbin.com/tonapaqi/1#/test/1

http://emberjs.jsbin.com/tonapaqi/1#/test/2

hbs - 使用所需的上下文调用{{view}}帮助器,如果它包含template属性,则初始默认模板将更改。 < / p>

{{view App.PreviewTemplateView contextBinding="this"}}

<强> JS

App.Router.map(function() {
  this.route("test",{path:"test/:tmpl_id"});
});

App.IndexRoute = Ember.Route.extend({
  beforeModel: function() {
    this.transitionTo("test",1);
  }
});
App.TestRoute = Ember.Route.extend({
  model:function(params){
    if(params.tmpl_id==1){
      return {template:"this is template 1 <b>{{view.parentView.parentVar}},param from context of model:{{someParams.param1}}</b>",someParams:{param1:"p1",param2:"p2"}};
    }else{
      return {template:"this is template 2 <b>{{view.parentView.parentVar}},param from context of model:{{someParams.param2}}</b>",someParams:{param1:"p1",param2:"p2"}};
    }
  }

});

App.PreviewTemplateView = Ember.View.extend({
    template:Ember.Handlebars.compile("initial default template"),
  init:function(){
    this._super();
    this.refreshTemplate();
  },
  refreshTemplate:function(){
    this.set("template",Ember.Handlebars.compile(this.get("context").get("template")));
    this.rerender();
  }.observes("context.template")
});

App.TestView = Ember.View.extend({
  parentVar:"this is a parent variable"
});

答案 1 :(得分:2)

我最终选择了一个Handlebars助手。似乎更灵活。

我使用EAK和Coffeescript:

helper = Ember.Handlebars.makeBoundHelper (template, context) ->

dummy = Ember.View.extend
  context: context
  template: Ember.Handlebars.compile template
view = dummy.create()
$elem = null
Ember.run ->
  $elem = $('<div>')
  view.appendTo($elem)

return new Handlebars.SafeString $elem.html()

现在在任何模板中我都可以写

{{preview-template template context}}

其中template是(可能是用户生成的)模板,context数据。