1

Mates I have the following:

App.Collections.Bookings = Backbone.Collection.extend({
url: 'bookings/',
model: App.Models.Booking,

howManyArriving: function() {

    var bg = _.countBy( this.models, function(model) {
        return model.get('indate') == moment().format('YYYY-MM-DD') ? 'even' : 'odd';
    });

    var lv = _.filter( this.models, function(model){
        return model.get('indate') == moment().format('YYYY-MM-DD');
    });

    var r = {
        count: bg,
        models: lv
    }
    return r;
},

availableBtwn: function(bed,indate,outdate) {
    var gf = _.filter(this.models, function(model){
        return (
            model.get('outdate') > outdate &&
            model.get('indate') <= indate &&
            model.get('id_bed') == bed
        );
    });
    return gf;
},

getBooking: function(bed, date){

    var gf = _.filter(this.models, function(model){
        return (
            model.get('outdate') > date &&
            model.get('indate') <= date &&
            model.get('id_bed') == bed
        );
    });
    return gf;
},

getFullName: function(id){
    var b = this.get(id);
    return b.get('nombre') + ' ' + b.get('apellido');
}
});

I need to check when I populate the collection and when I add a single model if there's already an existing model with determined propperties equal to the model/s that i'm attempting to create. I've tried something like this:

App.Collections.Bookings.prototype.add = function(bookings) {
_.each( bookings, function(book){
    var isDupe = this.any(function(_book) { 
        return _book.get('id') === book.id;
    });
    if (isDupe) {
        //Up to you either return false or throw an exception or silently ignore
        return false;
    }else{
        Backbone.Collection.prototype.add.call(this, book);
    }
    //console.log('Cargo el guest: ' + guest.get('id'));
}, this);

}

The thing is, it works, but when I populate the collection, it's not populated by App.Models.Booking, but with response's JSON.

Any idea?

Thanks a lot!

4

1 回答 1

3

So, basically when you populate a collection, 3 flags are describing the behavior your method should have: add, remove, merge . We'll start by the default behavior of the set and add methods:

// Default options for `Collection#set`.
var setOptions = {add: true, remove: true, merge: true};
var addOptions = {add: true, merge: false, remove: false};

The add method in fact proxies the set method, as does the fetch method if you don't use the reset flag (which would cause to delete any model in your collection and create new ones each time you fetch them) which would call the reset method instead.

Now, how to use the flags. Well, it's the options specified in the doc. So basically, the default behavior for the add method is equivalent to this:

myCollection.add(myModels, {add: true, merge: false, remove: false});

Now, for the meaning of those flags:
- add: will add the news models (=the ones their id is not among the existing ones...) to the collection
- remove: will remove the old models (=the ones their id is not among the fetched models) of the collection
- merge: will update the attributes of the ones among the old and the fetched

What you should know about the merge flag: IT'S A REAL PAIN IN THE ASS. Really, I hate it. Why ? Because it uses an internal function that "prepares the models" :

if (!(model = this._prepareModel(models[i], options))) continue;

It means that it will create fake, volatile models. What's the big deal? Well, it means that it will execute the initialize function of those volatile models, possibly creating a chain reaction and unwanted behavior in your app.

So, what if you want this behavior but can't have volatile models created because it breaks your app? Well, you can set the merge flag to false and override the parse method to do it, something like:

parse: function(models) {
  for(var i=0; i<models.length; i++) {
    var model;
    if(model = this.get(models[i].id)) {
      model.set(models[i]);
    }
  }
  return models;
}
于 2013-03-30T14:55:04.810 回答