• 基于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 貌似比较复杂,有兴趣的可以自己上网搜一下,我现在也只是一知半解。

  • 相关阅读:
    Overloaded的方法是否可以改变返回值的类型
    parseXXX的用法
    java的类型转换问题。int a = 123456;short b = (short)a;System.out.println(b);为什么结果是-7616?
    UVA 10405 Longest Common Subsequence(简单DP)
    POJ 1001 Exponentiation(大数处理)
    POJ 2318 TOYS(计算几何)(二分)
    POJ 1265 Area (计算几何)(Pick定理)
    POJ 3371 Flesch Reading Ease (模拟题)
    POJ 3687 Labeling Balls(拓扑序列)
    POJ 1094 Sorting It All Out(拓扑序列)
  • 原文地址:https://www.cnblogs.com/hiddenfox/p/2648017.html
Copyright © 2020-2023  润新知