1

Today I updated backbone.js (0.9.2 => 0.9.9) and backbone-relational (0.5.0 => 0.7.0), and a piece of code stopped working and I can't figure our why. (I even tried to upgrade step by step (e.g. backbone-relational 0.5.0 => 0.6.0), but that didn't helped.)

My models (a book that contains several chapters):

window.Book = Backbone.RelationalModel.extend({
  relations:[{
    type: Backbone.HasMany,
    key:"chapters",
    relatedModel: "Chapter",
    collectionType:"ChaptersCollection",
    reverseRelation:{
      key:"book"
    }
  }]
});

window.BookCollection = Backbone.Collection.extend({
  model: Book,
  url: "/books"
});

window.Chapter = Backbone.RelationalModel.extend();
window.ChaptersCollection = Backbone.Collection.extend({
  model: Chapter,
  url: "/chapters"
});

Now I want to add a chapter to an existing book, and do something during the "add" event. The problem is that chapter.get("book")is undefined, although the book is returned in the successcallback. But see yourself:

var book = ...;
book.get("chapters").on("add", function (chapter) {
  console.log("add");
  console.log(chapter.get("id"));
  console.log(chapter.get("book_id"));
  console.log(chapter.get("book"));
});

var chapter = book.get("chapters").create({title:"Foo"}, {
  wait: true,
  success:function () {
    console.log("success")
    console.log(chapter.get("id"));
    console.log(chapter.get("book_id"));
    console.log(chapter.get("book"));
  }
});    

Console output:

> add
> 83
> 3
> null <<<<<<< Expecting a book object here, why null?
> success
> 83
> 3
> Book{...}

Do you have any idea what I am doing wrong?

lacco
  • 882
  • 1
  • 10
  • 24
  • Could be that the relation initialization hasn't occurred yet when the add event fires. Try `_.defer(function() { console.log(chapter.get("book")); });` and see if it logs the book. If it does, that's your culprit. – jevakallio Jan 11 '13 at 14:45
  • Defering the call is working, but it won't help me: I am using ```Marionette.CollectionView``` (https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.collectionview.md) that automatically renders items on add, so I have to look for another workaround :( – lacco Jan 12 '13 at 18:36
  • It wasn't meant as a workaround, just a way to check whether that was the problem. I'll see if I have time to look at this later. – jevakallio Jan 12 '13 at 18:52

1 Answers1

1

The issue seems to be that when the add event is fired for the child collection, the reverse relation hasn't yet been updated. I'm not sure what change in Backbone or Backbone.Relational between versions caused this change, but it's easy to fix.

Instead of listening to the add event on the related collection like you do here:

book.get("chapters").on("add", function (chapter) {

You should listen to the add:<key> event on the model itself as described in the Backbone.Relational documentation:

book.on("add:chapters", function (chapter) {

Check out this fiddle for a working example.

jevakallio
  • 35,324
  • 3
  • 105
  • 112
  • Thank you very much, this worked great! Using the ```add:```event I could hook into https://github.com/marionettejs/backbone.marionette/blob/master/lib/backbone.marionette.js#L1321 ! – lacco Jan 14 '13 at 10:50