如何在一个集合中跟踪模型的数量,并与服务器保持同步,使用AMD改变Backbone.js



这里是Backbone.js新手。一般性问题:跟踪集合中模型的数量以便在UI上显示它的最佳实践是什么?我的用例可能涉及服务器端的更改,因此每次集合同步时,我都需要能够从存储中将UI更新为正确的数字。

我使用的是Backbone.js v1.0.0和Underscore v1.4.4从amdjs项目和Require.js v2.1.6.

具体示例:简单的购物车显示"购物车中的商品数量",当用户添加/删除商品时,该购物车会不断更新。在这个例子中,我几乎做到了,但是(1)我的代码总是比实际的模型数量少一个;(2)我觉得有更好的方法来做到这一点!

这是我的新手代码。首先,我有一个物品集合,用户可以通过一个按钮将其添加到购物车中。(注意:为了简洁起见,代码示例中删除了所有AMD定义和返回。)

var PackagesView = Backbone.View.extend({
el: $("#page"),
events: {
  "click .addToCart": "addToCart"
},
initialize: function(id) {
  this.collection = new PackagesCollection([],{id: id.id});
  this.collection.fetch({
    reset: true
  });
  this.collection.on("reset", this.render, this);
},
render: function(){
//other rendering stuff here
..............
  //loop through models in collection and render each one
  _.each(this.collection.models, function(item){
    that.renderPackages(item);
  });
}
renderPackages: function(item){
  var packageView = new PackageView({
    model: item
  });
  this.$el.append(packageView.render().el);
},

接下来,我有购物车PackageView中每个单独项目的视图,该视图由上面的PackagesView代码调用。我有一个"添加到购物车"按钮,每个包有一个"点击"事件绑定到它。

var PackageView = Backbone.View.extend({
tagName:"div",
template:$(packageTemplate).html(),
events: {
  "click .addToCart": "addToCart"
},
render:function () {
    var tmpl = _.template(this.template);
    this.$el.html(tmpl(this.model.toJSON()));
    return this;
},
addToCart:function(){
  cartView = new CartView();
  cartView.collection.create(new CartItemModel(this.model));
}

最后,我有一个CartView,它包含购物车中所有商品的集合。我尝试添加一个listenTo方法来对集合的更改做出反应,但它也没有与服务器保持同步。

var CartView = Backbone.View.extend({
el: $("#page"),
initialize:function(){
  this.collection = new CartCollection();
  this.collection.fetch({
    reset: true
  });

  this.listenTo(this.collection, 'add', this.updateCartBanner);
  this.collection.on("reset", this.render, this);
},
render: function(){
  $('#cartCount').html(this.collection.length);
},
updateCartBanner: function(){
  //things did not work here. Just putting this here to show something I tried.
}

具体示例的最终结果: .create工作正常,PUT请求发送,服务器将数据添加到数据库中,"reset"事件被调用。然而,CartView中的render()函数没有显示集合中模型的正确#。第一次单击"添加到购物车"按钮时,$('#cartCount')元素没有被填充。在那之后的任何时间,它都被填充了但我从服务器上的实际计数中减去了1。我相信这是因为我有一个。create和一个。fetch,而。fetch是在。create完成之前发生的,所以我总是比服务器慢1。

最终结果是,我没有以正确的方式构建它。任何正确方向的提示都会很有帮助!

你可以这样尝试:

collection.on("add remove reset sync", renderCallback)

其中renderCallback是刷新UI的函数

找到了我的问题的答案,但肯定是一个更好的方法。

如果我改变我的代码,而不是像我上面那样为集合中的每个模型单独的视图,我有一个遍历所有模型并绘制的视图,那么它将工作。我仍然需要调用一个。create,然后是一个。fetch,有一些意想不到的行为,但最终结果是正确的。请注意,在这段代码中,我已经完全取消了之前的PackageView,现在所有内容都由PackagesView绘制。

var PackagesView = Backbone.View.extend({
el: $("#page"),
events: {
  "click .addToCart": "addToCart"
},
initialize: function(id) {
  this.collection = new PackagesCollection([],{id: id.id});
  this.collection.fetch({
    reset: true
  });
  this.collection.on("reset", this.render, this);
},
render: function(){
  var that = this;
  var tmpl = _.template($(packageTemplate).html());
  //loop through models in collection and render each one
  _.each(this.collection.models, function(item){
    $(that.el).append(tmpl(item.toJSON()));
  });
},
addToCart:function(e){
  var id= $(e.currentTarget).data("id");
  var item = this.collection.get(id);
  var cartCollection = new CartCollection();
  var cartItem = new CartItemModel();
  cartCollection.create(new CartItemModel(item), {
    wait: true,
    success: function() {
      console.log("in success create");
      console.log(cartCollection.length);
    },
    error:function() {
      console.log("in error create");
      console.log(cartCollection.length);   
    }
  });
  cartCollection.fetch({
    wait: true,
    success: function() {
      console.log("in success fetch");
      console.log(cartCollection.length);
      $('#cartCount').html(cartCollection.length);
    },
    error:function() {
      console.log("in error fetch");
      console.log(cartCollection.length);   
    }
  });  

Result: .fetch回调中的$('#cartCount')注入模型的修正数。出乎意料的是,随着正确的。html()值Chrome console.log返回是(服务器端在数据库中没有模型开始):

in error create PackagesView.js:88
0 PackagesView.js:89
in success fetch PackagesView.js:97
1 

我从创建中得到了一个200的响应,所以对于两个回调都应该是"成功"。我本以为创建和获取的主干回调语法是相同的。哦,好吧,好像还行。

对此方法的任何反馈都是值得赞赏的!可能是更好的方法。

顺便说一下,这违背了这里的一般建议,尽管我确实有一个"非常简单的列表",所以也许从长远来看它是OK的。

最新更新