Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Backbone can an attribute contain a collection?

In backbone what is the desired way to store the relationship (in localstorage) between an author and books.

Is it possible to have a collection as an attribute or should an array be used or...?

var book = Backbone.Model.extend({ 
    defaults:{ 
        title: ''
    }
});

var books = Backbone.Collection.extend({
    model: book
});


var author = Backbone.Model.extend({
        defaults:{ 
        firstName: '',
        lastName: '', 
        books: new books()
        }
});

var authors = Backbone.Collection.extend({
    model: author,
    localStorage: new Backbone.LocalStorage("authors")
});
like image 803
Nicholas Murray Avatar asked Feb 17 '23 21:02

Nicholas Murray


1 Answers

There is no One True Way of handling nested collections in Backbone. Quoting from Backbone FAQ:

Backbone doesn't include direct support for nested models and collections or "has many" associations because there are a number of good patterns for modeling structured data on the client side, and Backbone should provide the foundation for implementing any of them.

The FAQ also suggests one pattern and provides a link to the Extensions, Plugins, Resources page, which links to many libraries you can use for handling nested models and model relations.

That said, I have sometimes approached the problem like this:

var Author = Backbone.Model.extend({

  initialize: function(attrs, options) {
    //convert the child array into a collection, even if parse was not called
    var books = attrs ? attrs.books : [];
    if(!(books instanceof Books)) {
        this.set('books', new Books(books), {silent:true});
    }
  },

  //the books property does not need to be declared in the defaults
  //because the initialize method will create it if not passed
  defaults: {
    firstName: '',
    lastName: ''    
  },

  //override parse so server-sent JSON is automatically
  //parsed from books array to Books collection
  parse: function(attrs) {
    attrs.books = new Books(attrs.books);
    return attrs;
  },

  //override toJSON so the Books collection is automatically
  //converted to an array 
  toJSON: function() {
    var json = Backbone.Model.prototype.toJSON.call(this);
    if(json.books instanceof Books) {
      json.books = json.books.toJSON();
    }
    return json;
  }
});

The comments hopefully explain how it works, but the point is that you can use the model as you would normally: initialize the children with a collection, an array or nothing, get the from a server, send them to the server, it should all work transparently. There's quite a bit of boilerplate code to write, but it's relatively simple to abstract into a base class, if you find yourself repeating the same code.

Edit: Small correction, you don't need the books defined in the defaults object, because the constructor creates it if missing.

/code sample not tested

like image 104
jevakallio Avatar answered Feb 20 '23 10:02

jevakallio