将Backbone.js集合呈现为下拉列表

16

我正在尝试使用Underscore.js模板将一个Backbone.js集合渲染成一个select列表,但是该列表未被填充。 select元素正在显示,但没有options

我已确认能够将单个属性传递到我的模板中并将它们呈现为label元素,因此问题必须在于我如何处理集合。

以下是我的Backbone代码:

Rate = Backbone.Model.extend({
    duration : null
});

Rates = Backbone.Collection.extend({
    initialize: function (model, options) {
    }
});

AppView = Backbone.View.extend({
    el: $('#rate-editor-container'),
    initialize: function () {
      this.rates = new Rates(null, { view: this } );

      this.rates.add(new Rate ({ duration: "Not Set" }));
      this.rates.add(new Rate ({ duration: "Weekly" }));
      this.rates.add(new Rate ({ duration: "Monthly" }));

      this.render();
    },
    render: function() {
      var rate_select_template = _.template($("#rate_select_template").html(), {rates: this.rates, labelValue: 'Something' });
      $('#rate-editor-container').html(rate_select_template);
    },
});

var appview = new AppView();

我的模板:

<script type="text/template" id="rate_select_template">
  <select id="rate-selector"></select>
  <% _(rates).each(function(rate) { %>
    <option value="<%= rate.duration %>"><%= rate.duration %></option>
  <% }); %>
</script>

<div id="rate-editor-container"></div>

有什么建议吗?


请在您的渲染函数中仔细检查“this”的值 - 我没有看到您将其绑定到Backbone对象。您可以在初始化函数中使用_.bindAll(this,'render')来完成它。 - Factor Mystic
嗯,我在我的Backbone.View扩展中刚刚添加了this.render()上面的代码,但好像没有任何作用。在发布问题之前,我执行了console.log(this.rates),输出为带有三个子对象的child。因此,我认为我正在传递某种带有三个嵌套对象的对象,这似乎是正确的。 - Josh Earl
@Factor: 在最新版本的Backbone中,delegateEvents自己进行绑定(在最新源代码中查找method = _.bind(method, this);),因此您不再需要通常的_.bindAll操作来启动您的initialize方法。 - mu is too short
1个回答

34

您有几个不同的问题。

  1. 您的模板试图将 <option> 元素放在 <select> 后面而不是其中。这将生成无效的HTML,一旦从模板中获取任何内容,浏览器将会对其进行处理。
  2. rates 是一个 Backbone 集合,因此它已经可以访问Underscore 的 each; 将它包装为 _(rates) 只会混淆 Underscore 并阻止任何迭代发生。
  3. 在迭代过程中,rate 是一个 Backbone 模型实例,因此它将没有一个 duration 属性,您必须使用 rate.get('duration')

您的模板应该看起来更像这样:

<script type="text/template" id="rate_select_template">
    <select id="rate-selector">
        <% rates.each(function(rate) { %>
            <option value="<%= rate.get('duration') %>"><%= rate.get('duration') %></option>
        <% }); %>
    </select>
</script>

示例:http://jsfiddle.net/ambiguous/AEqjn/

或者,您可以仅修复模板中的嵌套错误以生成有效的HTML:

<script type="text/template" id="rate_select_template">
    <select id="rate-selector">
        <% _(rates).each(function(rate) { %>
            <option value="<%= rate.duration %>"><%= rate.duration %></option>
        <% }); %>
    </select>
</script>

在视图中使用 toJSON(),将原始数据提供给模板,而不是集合本身:

var rate_select_template = _.template($("#rate_select_template").html(), {
    rates: this.rates.toJSON(),
    labelValue: 'Something'
});

示例:http://jsfiddle.net/ambiguous/VAxFW/

我认为后者是你的目标,因为这是在Backbone中使用模板的更标准的方法。


6
非常感谢您提供清晰的解释。我无法相信自己错过了select嵌套的问题。Backbone.js看起来会很棒,但是对于一些非常基础的东西,例如这个问题,很难找到示例。像待办事项应用程序这样的示例应用程序中有很多内容,很难看清每个部分的作用。感谢您的帮助。 :) - Josh Earl
4
@Josh:一旦你掌握了基本模式,和它一起工作就会变得很容易。当然,要学习这些基本模式的唯一方法就是犯错误。 - mu is too short

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接