From fb837d3f3ebd9f44e25b5f514e934e4870631a25 Mon Sep 17 00:00:00 2001 From: Paul Uithol Date: Wed, 6 Mar 2013 14:10:54 +0100 Subject: [PATCH] Fix a bug where `reverseRelation` initialization gets deferred. Fixes #285 --- backbone-relational.js | 11 ++++-- test/tests.js | 85 ++++++++++++++++++++++++++++++------------ 2 files changed, 70 insertions(+), 26 deletions(-) diff --git a/backbone-relational.js b/backbone-relational.js index 7a72a888..4f2910b8 100755 --- a/backbone-relational.js +++ b/backbone-relational.js @@ -1039,17 +1039,22 @@ // collection events only after the model is really fully set up. // Example: "p.get('jobs').add( { company: c, person: p } )". if ( options && options.collection ) { - var dit = this; + var dit = this, + collection = this.collection = options.collection; + + // Prevent this option from cascading down to related models; they shouldn't go into this `if` clause. + delete options.collection; + this._deferProcessing = true; var processQueue = function( model ) { if ( model === dit ) { dit._deferProcessing = false; dit.processQueue(); - options.collection.off( 'relational:add', processQueue ); + collection.off( 'relational:add', processQueue ); } }; - options.collection.on( 'relational:add', processQueue ); + collection.on( 'relational:add', processQueue ); // So we do process the queue eventually, regardless of whether this model actually gets added to 'options.collection'. _.defer( function() { diff --git a/test/tests.js b/test/tests.js index 2020839f..a51b4ee3 100644 --- a/test/tests.js +++ b/test/tests.js @@ -95,7 +95,7 @@ $(document).ready(function() { includeInJSON: [ 'id', 'name' ] } }, - { // A simple HasMany without recursive relation + { // A simple HasMany without reverse relation type: Backbone.HasMany, key: 'visitors', relatedModel: 'Visitor' @@ -258,6 +258,10 @@ $(document).ready(function() { }); + /** + * Node/NodeList + */ + window.Node = Backbone.RelationalModel.extend({ urlRoot: '/node/', @@ -280,6 +284,11 @@ $(document).ready(function() { model: Node }); + + /** + * Customer/Address/Shop/Agent + */ + window.Customer = Backbone.RelationalModel.extend({ urlRoot: '/customer/', @@ -2599,14 +2608,14 @@ $(document).ready(function() { var indexes = []; - zoo.get("animals").on("add", function(model, collection, options) { - var index = collection.indexOf(model); + zoo.get( 'animals' ).on( 'add', function( model, collection, options ) { + var index = collection.indexOf( model ); indexes.push(index); }); - zoo.set("animals", [ + zoo.set( 'animals', [ { id : 1, species : 'Lion' }, - { id : 2, species : 'Zebra'} + { id : 2, species : 'Zebra' } ]); equal( indexes[0], 0, "First item has index 0" ); @@ -3114,29 +3123,59 @@ $(document).ready(function() { //console.log( person, user ); }); - test( "ReverseRelations are applied retroactively (2)", function() { - var models = {}; - Backbone.Relational.store.addModelScope( models ); + test( "ReverseRelations are applied retroactively (2)", function() { + var models = {}; + Backbone.Relational.store.addModelScope( models ); - // Use brand new Model types, so we can be sure we don't have any reverse relations cached from previous tests - models.NewPerson = Backbone.RelationalModel.extend({ - relations: [{ - type: Backbone.HasOne, - key: 'user', - relatedModel: 'NewUser', - reverseRelation: { + // Use brand new Model types, so we can be sure we don't have any reverse relations cached from previous tests + models.NewPerson = Backbone.RelationalModel.extend({ + relations: [{ type: Backbone.HasOne, - key: 'person' - } - }] + key: 'user', + relatedModel: 'NewUser', + reverseRelation: { + type: Backbone.HasOne, + key: 'person' + } + }] + }); + models.NewUser = Backbone.RelationalModel.extend({}); + + var user = new models.NewUser( { id: 'newuser-1', person: { id: 'newperson-1' } } ); + + equal( user.getRelations().length, 1 ); + ok( user.get( 'person' ) instanceof models.NewPerson ); }); - models.NewUser = Backbone.RelationalModel.extend({}); - var user = new models.NewUser( { id: 'newuser-1', person: { id: 'newperson-1' } } ); + test( "Deep reverse relation starting from a collection", function() { + var nodes = new NodeList([ + { + id: 1, + children: [ + { + id: 2, + children: [ + { id: 3 } + ] + } + ] + } + ]); + + var parent = nodes.first(); + ok( parent, 'first item accessible after resetting collection' ); - equal( user.getRelations().length, 1 ); - ok( user.get( 'person' ) instanceof models.NewPerson ); - }); + ok( parent.collection === nodes, '`parent.collection` is set to `nodes`' ); + + var child = parent.get( 'children' ).first(); + ok( child, '`child` can be retrieved from `parent`' ); + ok( child.get( 'parent' ), 'reverse relation from `child` to `parent` works'); + + var grandchild = child.get( 'children' ).first(); + ok( grandchild, '`grandchild` can be retrieved from `child`' ); + + ok( grandchild.get( 'parent' ), 'reverse relation from `grandchild` to `child` works'); + }); module( "Backbone.Collection", { setup: reset } );