3

给定一个模型:

MyModel = Backbone.Model.extend({
  defaults: {
    name: '',
    age: -1,
    height: '',
    description: ''
  }
});

以及将模型呈现为列表的视图:

MyView  = Backbone.View.extend({
  tagName: 'ul',
  className: 'MyView',

  render() {
    var values = {
      name: this.model.get('name'),
      age: this.model.get('age'),
      height: this.model.get('height'),
      description: this.model.get('description')
    }

    var myTemplate = $('#MyView-Template').html();
    var templateWithValues = _.template(myTemplate , values);
  }
});

和视图加载的模板:

<script type="text/template" id="MyView-Template">  
  <li class="name"><%= name %></li>
  <li class="age"><%= age %></li>
  <li class="name"><%= height%></li>
  <li class="name"><%= description%></li>
</script>

一切正常,虽然这是一个人为的例子,但真实的代码在模型中有很多很多的属性。我遇到的问题是如何处理模型的更新。

我创建了一个 HTML 表单,其中每个字段都有一个适当的输入元素。该表单被建模并作为模板加载:

<script type="text/template" id="MyEditView-Template">  
  <input type"text" value="<%= name %>" /> <br />
  <input type"text" value="<%= age%>" /> <br />
  <input type"text" value="<%= height%>" /> <br />
  <input type"text" value="<%= description%>" /> 
</script>

并加载到视图中:

MyEditView  = Backbone.View.extend({
      tagName: 'form',
      className: 'MyEditView',

      render() {
        var values = {
          name: this.model.get('name'),
          age: this.model.get('age'),
          height: this.model.get('height'),
          description: this.model.get('description')
        }

        var myTemplate = $('#MyEditView-Template').html();
        var templateWithValues = _.template(myTemplate , values);
      }
    });

当用户保存表单时,新值会在模型 (MyModel) 中设置。但是我不想重新渲染整个原始视图,它需要太长时间并且有很多嵌套元素。我只想更新在模型中更改了其值的 HTML 元素。

问题是如何优雅地将模型的属性链接到 HTML 元素,以便我可以对已渲染的视图执行以下操作:

  1. 迭代模型的属性。
  2. 确定哪些属性已被修改。
  3. 仅更新已修改属性的 UI。
  4. 隐藏任何以前呈现的不应再显示的属性的 UI。

有一刻我有一个 JavaScript 查找表(只是一个对象)的相当丑陋的解决方案,它将属性名称映射到 HTML 元素字符串:

var AttributesMap = {
    name: {
        htmlRef: 'li.name',
        attributeName: 'name'
    },
    age: {
        htmlRef: 'li.age',
        attributeName: 'age'
    }
    ...
}

这感觉很hacky,并导致了一些非常臃肿的代码。

4

3 回答 3

6

您的帖子中实际上隐藏了两个问题。您对模型的属性有疑问,并且您不知道如何订阅模型更改事件。幸运的是,使用backbone.js 可以轻松实现这两者。将您的视图代码更改为以下

1

render: function () {
    var model = this.model;
    $(this.el).empty().html(_.template(this.template, this.model.toJSON()))
    return this;
}

whereel是定义容器的视图的属性。toJSON()是一种方法,您可以在模型上调用以序列化可以通过网络传输的格式。

2

视图应该在其初始化函数中订阅模型更改事件,或者更恰当地使用委托事件支持。当模型属性发生变化时,会在该模型上调用一个change事件,您可以像这里和下面的示例一样订阅该事件。

window.ListView = Backbone.View.extend({
    initialize: function () {
        //pass model:your_model when creating instance
        this.model.on("change:name", this.updateName, this);
        this.model.on("change:age", this.changedAge, this);
    },
    render: function () {
        var model = this.model;
        $(this.el).empty().html(_.template(this.template, this.model.toJSON()))
        return this;
    },
    updateName: function () {
        alert("Models name has been changed");
    },
    changedAge: function () {
        alert("Models age has been changed");
    }
});

JsBin 示例

http://jsbin.com/exuvum/2

于 2012-05-07T05:31:03.770 回答
1

我遇到了一个类似的问题,我希望模板只显示有数据的字段。我从下划线模板方面解决了这个问题,因为 <%= undefinedKey %> 引发了异常。对我来说,解决方案是将包装器对象传递给包含模型数据的模板。模型数据的包装如下所示:

this.$el.html(this.template({my_data: this.model.toJSON()}));

您的模板检查是否存在所需的属性:

<% if(my_data.phone) { %><p><%= my_data.phone %> </p><% } %>

每次模型更改时,您都可以自动渲染整个视图。使用此方法,新值将出现,删除的值将从 UI 中消失。

与您的要求相关的一些进一步信息:

迭代模型的属性。确定哪些属性已被修改。

如果您想知道自上次触发模型的“更改”事件以来哪些属性发生了变化,您可以使用主干模型的 changedAttributes方法。

仅更新已修改属性的 UI。隐藏任何以前呈现的不应再显示的属性的 UI。

代替为发生的每个属性更改渲染整个视图,您可以通过使每个 UI 字段成为离散的主干视图来仅更新 UI 中已更改属性的部分。所有视图都将监听共享模型以获取特定模型属性的更改事件:

    this.model.on("change:phone", this.render, this);
于 2012-11-16T22:34:33.257 回答
0

好吧,Backbone 使用事件委托,并且在替换 this.el 内容后不需要重新订阅元素事件。但是每次模板同步都会破坏 DOM 子树,这意味着您会丢失表单的状态。只需尝试为您的模型订阅输入/更改事件。所以用户输入输入元素和表单验证。恢复控件的状态(比如说 input[type=file])将是具有挑战性和资源匮乏的。

我相信最好的方法是使用基于 DOM 的模板引擎,它只在需要的地方更新目标元素。例如我的是https://github.com/dsheiko/ng-template

你可以有这样的模板:

<form id="heroForm" novalidate>
  <div class="form-group">
    <label for="name">Name</label>
    <input id="name" type="text" class="form-control" required >
    <div class="alert alert-danger" data-ng-if="!name.valid">
      Name is required
    </div>
  </div>
  <div class="form-group">
    <label for="power">Hero Power</label>
    <select id="power" class="form-control"  required>
      <option data-ng-for="let p of powers" data-ng-text="p" >Nothing here</option>
    </select>
    <div class="alert alert-danger" data-ng-if="!power.valid">
      Power is required
    </div>
  </div>
   <button type="submit" class="btn btn-default" data-ng-prop="'disabled', !form.valid">Submit</button>
</form>

在这里,我们绑定了模型namepower并且form。每当它们的状态发生变化时(例如,当用户键入时),模板就会做出反应。它可能隐藏/显示错误消息,或禁用/启用提交按钮。

如果它很有趣 - 如何将它与 Backbone 捆绑在一起,这里有一本免费的在线小书https://dsheiko.gitbooks.io/ng-backbone/

于 2016-08-27T14:24:14.783 回答