Last Updated: August 21, 2017
·
4.198K
· thure

How to deeply .reset() Backbone collections

If you've ever had to deal with a front-end ontology that involves great depth, à la Playlists > Playlist > Tracks > Track, and all you want to call is Playlists.reset( /* JSON received from server */ ), and you're using RequireJS, here's what you do:

Playlists:

define([
  'jquery'
  , 'underscore'
  , 'backbone'
  , '../models/playlist'
], function($, _, Backbone, Playlist){

  var playlists = Backbone.Collection.extend({

    model: Playlist

  });

  return new playlists;

});

Playlist

This is the important bit! When this model is constructed, its attributes will be set before its initialize function is called, so we reset its child collection at that time:

define([
  'jquery'
  , 'underscore'
  , 'backbone'
  , '../collections/tracks'
], function($, _, Backbone, Tracks){

  return Backbone.Model.extend({

    // Add this initialize func to reset this
    // model's child collection.
    initialize: function(){
      var tracks = new Tracks;
      this.set('tracks', tracks.reset(this.get('tracks')));
    }

  });

});

It's downhill from here…

Tracks:

define([
  'jquery'
  , 'underscore'
  , 'backbone'
  , '../models/track'
], function($, _, Backbone, Track){

  return Backbone.Collection.extend({
    model: Track
  });

});

Track:

define([
  'jquery'
  , 'underscore'
  , 'backbone'
], function($, _, Backbone){

  return Backbone.Model.extend({

  });

});

Et voilà! If you wanted to access a particular track, you'd do this:

Playlists.get('playlist').get('tracks').get('track');

The moral of the story is this: if you're resetting a collection whose models might themselves have collections, those models need to reset their collections with the JSON they received for that attribute. In theory, you could do this ad infinitum.