首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网站开发 > JavaScript >

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

2013-10-30 
基于Backbone.js的JavaScript MVC示例程序(6)一.概述二.REST Server的实现2.1 REST API设计2.2 数据库设计

基于Backbone.js的JavaScript MVC示例程序(6)
一.概述二.REST Server的实现2.1 REST API设计2.2 数据库设计2.3 用MyBatis实现的DAO层2.4 用Jersey实现的REST API2.5 用Spring AOP实现的日志功能三.前端的实现3.1 显示User列表3.2 显示User详细信息3.3 修改User信息3.4 增加User3.5 删除User3.6 添加validate3.3 修改User信息

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

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

想要实现点击"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 吧。

热点排行