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

来源:互联网 发布:网络pos机套现安全吗 编辑:程序博客网 时间:2024/04/29 22:31
  • 一.概述
  • 二.REST Server的实现
  • 2.1 REST API设计
  • 2.2 数据库设计
  • 2.3 用MyBatis实现的DAO层
  • 2.4 用Jersey实现的REST API
  • 2.5 用Spring AOP实现的日志功能
  • 三.前端的实现
  • 3.1 显示User列表
  • 3.2 显示User详细信息
  • 3.3 修改User信息
  • 3.4 增加User
  • 3.5 删除User
  • 3.6 添加validate

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

原创粉丝点击