Skip to content

Commit

Permalink
Merge pull request #174 from elasticsales/master
Browse files Browse the repository at this point in the history
Trigger appropriate add/remove/change events on bulk assignment
  • Loading branch information
DouweM committed Nov 16, 2012
2 parents 36178b8 + 2fbc6eb commit 4467670
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 16 deletions.
44 changes: 28 additions & 16 deletions backbone-relational.js
Original file line number Diff line number Diff line change
Expand Up @@ -878,11 +878,6 @@
options = this.sanitizeOptions( options );
this.keyContents = attr;

// Notify old 'related' object of the terminated relation
_.each( this.getReverseRelations() || [], function( relation ) {
relation.removeRelated( this.instance, options );
}, this );

// Replace 'this.related' by 'attr' if it is a Backbone.Collection
if ( attr instanceof Backbone.Collection ) {
this._prepareCollection( attr );
Expand All @@ -892,25 +887,42 @@
// Re-use the current 'this.related' if it is a Backbone.Collection, and remove any current entries.
// Otherwise, create a new collection.
else {
var coll;
var oldIds = {}, newIds = {};

if ( this.related instanceof Backbone.Collection ) {
coll = this.related;
coll.remove( coll.models );
if (!_.isArray( attr ) && attr !== undefined) {
attr = [ attr ];
}
else {
var oldIds;
_.each( attr, function( attributes ) {
newIds[ attributes.id ] = true;
});

var coll = this.related;
if ( coll instanceof Backbone.Collection ) {
// Make sure to operate on a copy since we're removing while iterating
_.each( coll.models.slice(0) , function( model ) {
// When fetch is called with the 'keepNewModels' option, we don't want to remove
// client-created new models when the fetch is completed.
if ( !options.keepNewModels || !model.isNew() ) {
oldIds[ model.id ] = true;
coll.remove( model, { silent: (model.id in newIds) } );
}
});
} else {
coll = this._prepareCollection();
}

_.each( attr, function( attributes ) {
var model = this.relatedModel.findOrCreate( attributes, { create: this.options.createModels } );
if (model) {
coll.add( model, { silent: (attributes.id in oldIds)} );
}
}, this);

this.setRelated( coll );
this.findRelated( options );

}

// Notify new 'related' object of the new relation
_.each( this.getReverseRelations() || [], function( relation ) {
relation.addRelated( this.instance, options );
}, this );

var dit = this;
Backbone.Relational.eventQueue.add( function() {
!options.silentChange && dit.instance.trigger( 'update:' + dit.key, dit.instance, dit.related, options );
Expand Down
61 changes: 61 additions & 0 deletions test/tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -2256,5 +2256,66 @@ $(document).ready(function() {
equal( zoo.get( 'name' ), 'Zoo Station' );
equal( lion.get( 'name' ), 'Simba' );
});


test( "Does not trigger add / remove events for existing models on bulk assignment", function() {
var house = new House({
id: 'house-100',
location: 'in the middle of the street',
occupants: [ { id : 'person-5' }, { id : 'person-6' } ]
});

var eventsTriggered = 0;
house
.bind( 'add:occupants', function(model) {
ok( false, model.id + " should not be added" );
eventsTriggered++;
})
.bind( 'remove:occupants', function(model) {
ok( false, model.id + " should not be removed" );
eventsTriggered++;
});

house.set( house.toJSON() );
ok( eventsTriggered === 0, "No add / remove events were triggered" )
});

test( "triggers appropriate add / remove / change events on bulk assignment", function() {
var house = new House({
id: 'house-100',
location: 'in the middle of the street',
occupants: [ { id : 'person-5', nickname : 'Jane' }, { id : 'person-6' }, { id : 'person-8', nickname : 'Jon' } ]
});

var addEventsTriggered = 0;
var removeEventsTriggered = 0;
var changeEventsTriggered = 0;

house
/*.bind( 'all', function(ev, model) {
console.log('all', ev, model);
})*/
.bind( 'add:occupants', function(model) {
ok( model.id === 'person-7', "Only person-7 should be added: " + model.id + " being added" );
addEventsTriggered++;
})
.bind( 'remove:occupants', function(model) {
ok( model.id === 'person-6', "Only person-6 should be removed: " + model.id + " being removed" );
removeEventsTriggered++;
});

var nicknameUpdated = false;
house.get('occupants').bind( 'change:nickname', function(model) {
ok( model.id === 'person-8', "Only person-8 should have it's nickname updated: " + model.id + " nickname updated" );
changeEventsTriggered++;
});

house.set( { occupants : [ { id : 'person-5', nickname : 'Jane'}, { id : 'person-7' }, { id : 'person-8', nickname : 'Phil' } ] } );

ok(addEventsTriggered == 1, "Exactly one add event was triggered (triggered "+addEventsTriggered+" events)");
ok(removeEventsTriggered == 1, "Exactly one remove event was triggered (triggered "+removeEventsTriggered+" events)");
ok(changeEventsTriggered == 1, "Exactly one change event was triggered (triggered "+changeEventsTriggered+" events)");
});

});

0 comments on commit 4467670

Please sign in to comment.