• 基于Backbone.js的JavaScript MVC示例程序(6)


    3.3 修改User信息

    界面如下,在右边 User 详细信息处增加了一个 "Edit" 按钮,点击之后下面的信息就变成了输入框,点击 "Submit" 完成修改,左侧列表随之更新。

    想要实现点击"Edit"将右侧详细信息的变为可编辑有几种方法:

    1. 创建一个 UserEditView 专门来显示修改User信息的表单;

    2. 点击 "Edit" 之后,将 UserInfoView 所绑定的 HTML 模板换成一个表单;

    3. Todos 这个例子里面给出了另外一种思路,它在 HTML 模板里面隐含了一个表单,默认情况下通过 css 将表单隐藏,点击 "Edit" 之后显示表单,并将非表单部分隐藏。

    本例中采用了第三种方法。

    3.html,在 user-info-template 模板中加入一个隐含的表单:

     1 <!-- user-info-template中加入编辑User信息的表单 -->
     2  <script type="text/template" id="user-info-template">
     3      <h3>User Information</h3>
     4      <button id="edit">Edit</button>
     5      <ul id="user-info">
     6          <li>ID:<span><%= id %></span></li>
     7          <li>Username:<span><%= username %></span><input type="text" name="username" value="<%= username %>" /></li>
     8          <li>Password:<span><%= password %></span><input type="password" name="password" value="<%= password %>" /></li>
     9          <li>Email:<span><%= email %></span><input type="text" name="email" value="<%= email %>" /></li>
    10          <li>Phone:<span><%= phone %></span><input type="text" name="phone" value="<%= phone %>" /></li>
    11          <button id="edit-submit">Submit</button>
    12      </ul>
    13  </script>

    mvc3.js

     1 $(document).ready(function() { 
     2      
     3      var User = Backbone.Model.extend({
     4      });
     5      
     6      var UserList = Backbone.Collection.extend({
     7          ... //不变
     8      });
     9      
    10      var UserItemView = Backbone.View.extend({
    11          tagName : "li",
    12          userItemTemplate : _.template($("#user-item-template").html()), 
    13          events : { 
    14                "click a" : "displayInfo",
    15          },
    16          initialize : function() { 
    17              //this.infoView = new UserInfoView({model : this.model}); //删除
    18              this.model.bind('change', this.render, this);  //新增,修改成功后会触发
    19          },
    20          render : function() {
    21              this.$el.html(this.userItemTemplate(this.model.toJSON()));
    22              return this;
    23          },
    24          /*displayInfo : function() { 
    25              this.infoView.render();
    26          },*/
    27          displayInfo : function() { //修改,注释一
    28              if(_.isEmpty(infoView)){
    29                  infoView = new UserInfoView({model : this.model});
    30              }else{
    31                  infoView.model = this.model;
    32                  infoView.model.unbind('change');
    33                  infoView.model.bind('change', this.render, this);
    34                  infoView.model.bind('change', infoView.render, infoView);
    35              }
    36              infoView.render();
    37          },
    38      });
    39      
    40      var UserInfoView = Backbone.View.extend({
    41          el : $("#right"),
    42          userInfoTemplate : _.template($("#user-info-template").html()),
    43          events : {
    44              "click #edit" : "displayEdit", //新增
    45              "click #edit-submit" : "submitEdit", //新增
    46          },
    47          initialize : function() {
    48              this.model.bind('change', this.render, this); //新增
    49          },
    50          render : function(){
    51              this.$el.html(this.userInfoTemplate(this.model.toJSON()));
    52              return this;
    53          },
    54          displayEdit : function() { //新增,改变 class,显示表单
    55              this.$("#user-info").addClass("editing");
    56          },
    57          submitEdit : function() { //新增,提交表单
    58              this.model.save({ //注释二
    59                  "username":$("input[name='username']").val(),
    60                  "password":$("input[name='password']").val(),
    61                  "email":$("input[name='email']").val(),
    62                  "phone":$("input[name='phone']").val(),
    63              });
    64              this.$("#user-info").removeClass("editing"); //改变 class,隐藏表单
    65          },
    66      });
    67      
    68      var UserListView = Backbone.View.extend({
    69          ... //不变
    70      });
    71      
    72      var userListView = new UserListView();
    73      var infoView;  //新增
    74  });

    注释一:

    在上一节中,每一个 UserItemView 都与一个 UserInfoView 一一对应,在显示User详细信息的时候是没有问题的,但是在修改User信息的时候会出现问题。因为多个 UserInfoView 绑定到了同一个 "Submit" 按钮上,所以在点击 "Submit" 的时候可能会更新好几个 User 的信息。

    解决的方法是声明一个全局的 UserInfoView(73行),在每一次点击列表中的 User 时,都将 UserInfoView 的 model 设置为当前点击的 User(31行),并且将当前的 UserItemView 和 UserInfoView 的 render() 方法绑定到这个 User 的 change 事件上(33-34行),并与之前的 User 解绑(32行),这样的话表单提交之后,左侧的列表和右侧的详细信息都会随之改变,而且也不会影响到其他 User。

    不知道会不会有更好的方法,欢迎交流。

    注释二:

    官网上对 model.save() 方法的解释如下:

    model.save([attributes], [options])
    通过委托 Backbone.sync 保存模型到数据库(或可替代的持久层)。 attributes 散列表 (在 set) 应当包含想要改变的属性,不涉及的键不会被修改。 如果模型含有 validate 方法,并且验证失败,模型不会保存。 如果模型 isNew, 保存将采用 "create" (HTTP POST) 方法, 如果模型已经在服务器存在,保存将采用 "update" (HTTP PUT) 方法。

    进一步看一下 isNew() 方法的解释:

    model.isNew()
    模型是否已经保存到服务器。 如果模型尚无 id,则被视为新的。

    在这里,被修改的 User 已经有 id 了,因此调用 model.save() 的时候自动向服务器发出 PUT 请求,请求中包含除了 id 之外的4个 attributes。

    Model 有一个 id,还有一个 cid,官方文档是这么说的:

    • model.id 模型的特殊属性, id 可以是任意字符串(整型 id 或 UUID)。 在属性中设置的 id 会被直接拷贝到模型属性上。 我们可以从集合(collections)中通过 id 获取模型,另外 id 通常用于生成模型的 URLs。
    • model.cid 模型的特殊属性,cid 或客户 id 是当所有模型创建时自动产生的唯一标识符。 客户 ids 在模型尚未保存到服务器之前便存在,此时模型可能仍不具有最终的 id, 客户 ids 的形式为:c1, c2, c3 ...

    也就是说 id 需要我们设置好,url() 方法会根据 id 来生成 Model 的 URL,这个 id 需要与 Server 端的 id 对应上,这样才能完成 GET/PUT/DELETE 请求。而 cid 我们并不需要去管它,实际上我们可以发现 View 也是有 cid 的。

    之前在 Server 端返回的 JSON 中,User 的信息中正好有个 id,我们试一试将 JSON 中的 id 换成 uid,会有什么反应。修改起来比较简单,只要把 com.demo.register.bean.User 的 id 属性改成 uid 就行了。我们可以发现,在页面提交 Edit 的表单之后,会发出 POST 请求,并新增一个 User,而不是修改了当前 User。再进一步查看 userList,发现里面的 User 都没有 id,所以 isNew() 的返回结果是 false,save() 的时候一直都是发出 POST 请求。

    通过重载 url() 和 isNew() 方法可以解决这个问题,只要将对 id 的判断改成对 uid 的判断就行了:

     1 // Default URL for the model's representation on the server -- if you're using Backbone's restful methods, override this to change the endpoint that will be called.
     2 url: function() {
     3     var base = getValue(this, 'urlRoot') || getValue(this.collection, 'url') || urlError();
     4     if (this.isNew()) return base;
     5     return base + (base.charAt(base.length - 1) == '/' ? '' : '/') + encodeURIComponent(this.id);
     6 },
     7 //重载之后:
     8 url: function() {
     9     var base = this.collection.url ;
    10     if (this.isNew()) return base;
    11     return base + (base.charAt(base.length - 1) == '/' ? '' : '/') + encodeURIComponent(this.uid);
    12 },
    13 
    14 // A model is new if it has never been saved to the server, and lacks an id.
    15 isNew: function() {
    16     return this.id == null;
    17 },
    18 //重载之后:
    19 isNew: function() {
    20     return this.attributes.uid == null;
    21 },

    当然这只是一个实验,最好还是不要去重载它,老老实实地使用 id 吧。

  • 相关阅读:
    简单字典操作
    字符串操作
    2017年10月7日
    循环列表练习
    Zabbix4.0系统告警"Zabbix agent on Zabbix server is unreachable for 5 minutes"
    Zabbix4.0系统告警“Zabbix server is not running”
    FreeRADIUS使用了在Cisco IOS配置示例的管理访问
    Cisco AAA Configuration
    使用工具Csvde导出域中所有用户信息
    McAfee Agent卸载方法
  • 原文地址:https://www.cnblogs.com/hiddenfox/p/2646716.html
Copyright © 2020-2023  润新知