如何在Ember.js中动态加载partials / views / templates

时间:2013-07-15 16:42:52

标签: javascript templates model-view-controller ember.js

所以我有以下设置。

在主页面上,基于来自使用夹具数据的模型的列表显示生成器列表。

现在,当单击其中一个生成器链接时,将显示一个新页面,其中包含一些基于该夹具数据动态生成的输入字段。

在此之前,一切都很完美。

现在,当我在生成器页面中更改输入字段的值(选择其中一个生成器之后)以查看正在我的输入字段下方的某种预览div中更新的更改时,这很容易。我可以使用{{generatorFields.0.value}}绑定第一个输入字段,.1。,依此类推,直到我绑定所有字段。

但是你可以想象,每个生成器都有自己的格式和自己的输入字段,我想为它们中的每一个创建一个新的.hbs文件,然后将该文件传递到生成器页面以显示预览。

我解决了部分问题的0.1%。在generator.hbs文件中,我输入{{partial "generator-1"}},这会加载包含_generator-3.hbs绑定的{{generatorFields.0.value}}文件,并且它可以正常工作。但那部分不是动态的;每次我使用不同的发生器时,我需要加载不同的部分。我怎样才能做到这一点?

如何动态传递部分名称或根据我拥有的模型数据加载模板?

目前使用的代码如下:

idex.hbs看起来像这样:

 <table class="table table-hover">
            <thead>
                <tr>
                    <th>#</th>
                    <th>Generator name</th>
                    <th>Action</th>
                </tr>
            </thead>
            <tbody>
                {{#each model}}
                <tr>
                    <td>{{id}}</td>
                    <td>{{title}}</td>
                    <td>{{#linkTo 'generator' this classNames="btn btn-mini pull-right"}}Create file{{/linkTo}}</td>
                </tr>
                {{/each}}
                </tbody>
        </table>

generator.hbs

{{#each generatorFields}}
<div class="row-fluid">
    <div class="span4">{{name}}</div>
    <div class="span8">{{view Ember.TextField valueBinding='value' class='span12' placeholder='Type value here…'}}</div>
</div>
{{/each}}

{{partial "generator-1"}}

_generator-1.hbs

<h1>Project: {{generatorFields.0.value}}</h1>

app.js

App.Store = DS.Store.extend({
    revision: 13,
    adapter: 'DS.FixtureAdapter'
});

App.Router.map(function () {
    this.resource('index', { path: '/' });
    this.resource('generator', {path: '/generator/:generator_id'});
});

App.IndexRoute = Ember.Route.extend({
    model: function () {
        return App.Generator.find();
    }
});

App.Generator = DS.Model.extend({
    title: DS.attr('string'),
    templateName:  DS.attr('string'),
    generatorFields: DS.attr('generatorFields')
});


// Fixture data

DS.RESTAdapter.registerTransform('generatorFields', {
    serialize: function(serialized) {
        return Em.none(serialized) ? {} : serialized;
    },
    deserialize: function(deserialized) {
        return Em.none(deserialized) ? {} : deserialized;
    }
});

App.Generator.FIXTURES = [{
    id: 1,
    title: "test 1",
    generatorFields: [
        {id: 1, name: "name 1", value: ""}
    ],
    templateName: "generator-1"
}, {
    id: 2,
    title: "test 2",
    generatorFields: [
        {id: 1, name: "name 1", value: ""},
        {id: 2, name: "name 2", value: ""},
    ],
    templateName: "generator-2"
}];

4 个答案:

答案 0 :(得分:15)

您可以使用传入的名称创建一个动态部分助手,以使用{{partial}}助手进行渲染。

Ember.Handlebars.helper('dynPartial', function(name, options) {
  return Ember.Handlebars.helpers.partial.apply(this, arguments);
});

然后使用此动态部分{{dynPartial}}代替。

{{#each item in controller}}
  {{dynPartial item.templateName}}
{{/each}}

对于templateName generator-1的生成器。这将使用部分_generator-1呈现。请注意,模板的id / data-template-name的名称必须以下划线开头。

答案 1 :(得分:5)

您应该能够简单地将动态部分变量放在部分帮助器中。

{{#each item in controller}}
    {{partial item.templateName}}
{{/each}}

正如@ darshan-sawardekar所指出的,如果你的templateName generator-1生成器_generator-1,它将呈现部分{{1}}。

答案 2 :(得分:1)

虽然@Darshan的答案比下面简单并且在很多情况下都有效,但我遇到了一个问题,如果第二个模型的部分名称是,那么转换到具有不同模型的相同路线会导致部分不重新渲染和第一个一样(ember中的bug?)。设置监视模型的视图可以解决此问题。

App.FooDynamicLayout = Ember.View.extend
  rerenderOnModelChange: (->
    @rerender()
  ).observes('model')

并将其命名为:

view App.FooDynamicLayout templateName=dynamicTemplateName model=model

答案 3 :(得分:0)

@KamrenZ已经提到了这一点,但我认为我会引用那些关注此事的章节和诗句。更新的Ember版本优雅地接受绑定属性名称并在部分帮助程序中使用它们:

http://ember-doc.com/classes/Ember.Handlebars.helpers.html#method_partial

  

BOUND TEMPLATE NAMES提供给partial的参数也可以是a   包含模板名称的属性的路径,例如:

{{partial someTemplateName}}
  

上面的例子将查找someTemplateName的值   模板上下文(例如控制器)并使用该值作为名称   要渲染的模板。如果解决的值是假的,那么什么都不会   被渲染。如果someTemplateName更改,则部分将更改   使用新模板名称重新渲染。