更新Backbone.js的查看变得一团糟(Updating Backbone.js View be

2019-07-29 06:35发布

给定一个模型:

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的应该不再显示任何先前渲染属性。

阿那一刻我有一个属性名称映射到一个HTML元素串一个JavaScript查找表(只是一个对象)的一个比较难看溶液:

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

这种感觉哈克并导致一些非常臃肿的代码。

Answer 1:

居然还有藏在你的后两个问题。 你必须与模型的属性问题,你不知道如果如何订阅模式变革的事件。 幸运的是,这两个都是可能容易与Backbone.js的。 您的视图代码更改为以下

1

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

其中el是限定容器的视图的属性。 的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



Answer 2:

我面对,我想有一个模板只显示其中有数据字段类似的问题。 我从下划线模板侧接近的问题,因为<%= 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);


Answer 3:

那么,骨干使用事件代表团和一个并不需要更换this.el内容后,再认购元素的事件。 但是,你破坏了DOM子树与每个模板的同步,这意味着你失去你的表单的状态。 刚刚尝试订阅模型输入/变更事件。 所以用户在输入元件和形式进行验证。 恢复控件的状态(假设输入[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>

在这里,我们结合车型namepowerform 。 每当他们的状态改变(例如当用户输入时),模板反应。 它可以隐藏/显示错误信息,或启用/禁用提交按钮。

如果这是有趣的-如何与骨干网捆绑它,这里是一个小免费的在线图书https://dsheiko.gitbooks.io/ng-backbone/



文章来源: Updating Backbone.js View becoming a mess
标签: backbone.js