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


    3.4 增加User

    左侧 User 列表上方添加了一个 "Add" 按钮,点击之后右侧的页面会显示一个增加 User 的表单,表单提交之后弹出一个提示框,左侧列表也会更新。如下图所示:

    4.html,新增了表单的模板和 "Add" 按钮:

     1 <!-- 增加User的表单 -->
     2 <script type="text/template" id="user-form-template">
     3     <h3>Add User</h3>
     4     <ul id="user-form" class="editing">
     5         <li>Username:<input type="text" name="username" /></li>
     6         <li>Password:<input type="password" name="password" /></li>
     7         <li>Email:<input type="text" name="email" /></li>
     8         <li>Phone:<input type="text" name="phone" /></li>
     9         <button id="add-submit">Submit</button>
    10     </ul>
    11 </script>
    12 ......
    13 <body>
    14     <div id="main">
    15         <div id="left">
    16             <h3></h3>
    17             <!-- 增加一个按钮,点击后显示增加User的表单 -->
    18             <p><button id="add">Add</button></p>
    19             <ul id="user-list"></ul>
    20         </div>
    21         <div id="right"></div>
    22     </div>
    23 </body>

    mvc4.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         ... //不变
     12     });
     13     
     14     var UserInfoView = Backbone.View.extend({
     15         ... //不变
     16     });
     17     
     18     var UserListView = Backbone.View.extend({
     19         el : $("#main"),
     20         userFormTemplate : _.template($("#user-form-template").html()), //新增,绑定模板
     21         events : {
     22               "click #add" : "displayUserForm", //新增
     23               "click #add-submit" : "submitUserForm", //新增
     24         },
     25         initialize : function() {
     26             this.userList = new UserList();
     27             this.userList.bind('add', this.addOne, this); //新增,每当userList中加一个User时,列表中会加一个条目
     28             this.userList.bind('reset', this.addAll, this);
     29             this.userList.bind('all', this.render, this); 
     30             this.userList.fetch({silent: true, success:function(collection, response){ 
     31                 if(response != null){
     32                     collection.reset(response.user);
     33                 }else{
     34                     userListView.render();
     35                 }
     36             }});
     37             this.displayUserForm(); //新增,加载页面的时候默认显示增加User的表单
     38         },
     39         render : function() {
     40             this.$("#left h3").html("Total Number:"+this.userList.length);
     41         },
     42         addOne : function(user) {
     43             var view = new UserItemView({model : user});
     44             this.$("#user-list").append(view.render().el);
     45         },
     46         addAll : function() { 
     47             this.userList.each(this.addOne);
     48         },
     49         displayUserForm : function() { //新增,显示增加用户的表单
     50             this.$("#right").html(this.userFormTemplate());
     51         },
     52         submitUserForm : function() { //新增,提交增加用户的表单
     53             var user  = new User({
     54                 "username":$("input[name='username']").val(),
     55                 "password":$("input[name='password']").val(),
     56                 "email":$("input[name='email']").val(),
     57                 "phone":$("input[name='phone']").val(),
     58             });
     59 
     60             /**** 注释一 报错:id is not defined *****
     61             this.userList.create(user);
     62             $("input[name='username']").val(""),
     63             $("input[name='password']").val(""),
     64             $("input[name='email']").val(""),
     65             $("input[name='phone']").val(""),
     66             alert("Add a user!");
     67             *****************************************/
     68             
     69             /************** 注释二 正确 *************/
     70             this.userList.create(user,{wait:true});
     71             $("input[name='username']").val(""),
     72             $("input[name='password']").val(""),
     73             $("input[name='email']").val(""),
     74             $("input[name='phone']").val(""),
     75             alert("Add a user!");
     76             /****************************************/
     77             
     78             /**** 注释三 报错:A "url" property or function must be specified ****
     79             user.save({success : function(){
     80                 $("input[name='username']").val(""),
     81                 $("input[name='password']").val(""),
     82                 $("input[name='email']").val(""),
     83                 $("input[name='phone']").val(""),
     84                 this.userList.add(user);
     85                 alert("Add a user!");
     86             }});
     87             **********************************************************************/
     88             
     89             /************** 注释四 正确 *************
     90             var ul = this.userList;
     91             user.urlRoot = "/backbone-sample/rest/user";
     92             user.save({},{success : function(){
     93                 $("input[name='username']").val(""),
     94                 $("input[name='password']").val(""),
     95                 $("input[name='email']").val(""),
     96                 $("input[name='phone']").val(""),
     97                 ul.add(user);
     98                 alert("Add a user!");
     99             }});
    100             *****************************************/
    101         },
    102     });
    103     
    104     var userListView = new UserListView();
    105     var infoView; 
    106 });

    注释一:

    如果使用第一段代码,会报错 “id is not defined”,让我们来找一下原因。

    官网上对于 create() 方法的解释如下:
    collection.create(attributes, [options]) 在集合中创建一个模型。等价于用键值对象实例一个模型,然后将模型保存到服务器,保存成功后将模型增加到集合中。如果验证失败会阻止模型创建,返回 false,否则返回该模型。为了能正常运行,需要在集合中设置 model 属性。create 方法接收键值对象或者已经存在尚未保存的模型对象作为参数。

    也就是先执行 user.save(),再执行 this.userList.add(user)。很显然 save() 会发送一个 AJAX 请求,因此如果它是个异步请求,在执行 add() 方法的时候很可能还未得到响应,而 add() 触发了 userList 的 add 事件,于是会执行与之绑定的 addOne() 方法,在显示页面元素的时候需要读取 id,因此会报“id is not defined”。

    注释二:

    为了解决注释一中的错误,我们来看一下如何将 create() 方法的 AJAX 请求变成一个同步请求。

    以下是 create() 方法的源码:

     1 // Create a new instance of a model in this collection. Add the model to the collection immediately, unless `wait: true` is passed, in which case we wait for the server to agree.
     2 create: function(model, options) {
     3     var coll = this;
     4     options = options ? _.clone(options) : {};
     5     model = this._prepareModel(model, options);
     6     if (!model) return false;
     7     if (!options.wait) coll.add(model, options);
     8     var success = options.success;
     9     options.success = function(nextModel, resp, xhr) {
    10     if (options.wait) coll.add(nextModel, options);
    11     if (success) {
    12       success(nextModel, resp);
    13     } else {
    14       nextModel.trigger('sync', model, resp, options);
    15     }
    16     };
    17     model.save(null, options);
    18     return model;
    19 },

    很显然如果 options.wait 为 false 时会直接将 model 加到 collection 中(7行),而 options.wait 为 true 的时候会在回调函数 success 执行的时候才将 model 加到 collection 中(10行)。

    因此解决方法很简单,就是在调用 create() 方法的时候加上参数 {wait:true}。

    注释三:

    注释一中已经分析过,执行 this.userList.create(user) 等价于先执行 user.save(),再执行 this.userList.add(user),因此我想到如果将 add() 方法的执行放到 save() 方法的 success 回调函数中,应该也能解决注释一中出现的错误。

    但是注释三中的代码报出了 “A "url" property or function must be specified” 的错误,原因是 User 的 url 需要通过 UserList.url 或 User.urlRoot 来生成,而这里的 user 在 save() 之前并没有被加到 UserList 中去, User.urlRoot 也并没有被赋值,因此得不到 url,无法发出 POST 请求。

    注释四:

    经过注释三的分析,我们知道只要在 user.save() 之前对 user.urlRoot 赋值就可以了,当然也可以直接在定义 User 模型的时候给他赋值,效果一样。

    注意这里先使用了一个临时变量 ul 来存放 this.userList,然后再 success 回调函数中使用的是 ul 而不是 this.userList。这样做并不是多此一举,因为在执行 success 回调函数的时候,this 所代表的对象已经不是 UserListView 了,而是 Window 对象。关于 JavaScript 里面的 this 貌似比较复杂,有兴趣的可以自己上网搜一下,我现在也只是一知半解。

  • 相关阅读:
    读 Kafka 源码写优雅业务代码:配置类
    如何安装FTP服务器,并实现文件共享
    Merge into用法总结
    Insomnia 跟 Postman 类似的软件
    iOS dealloc中初始化weak指针崩溃防护
    Centos7安装febootstrap
    获取 linux 系统 CPU、内存、磁盘 IO 等信息的脚本
    Git本地远程仓库
    网络及服务故障的排查思路
    Git配置远程仓库(密匙链接)
  • 原文地址:https://www.cnblogs.com/hiddenfox/p/2648017.html
Copyright © 2020-2023  润新知