How to load bootstrapped models in Backbone.js while using AMD (require.js)

Backbone.js documentation suggest loading bootstrapped models this way:

<script>
var Accounts = new Backbone.Collection;
Accounts.reset(<%= @accounts.to_json %>);
var Projects = new Backbone.Collection;
Projects.reset(<%= @projects.to_json(:collaborators => true) %>);
</script>

But this is a pattern that can't be used in AMD approach (using require.js)

The only possible solution is to declare global variable storing JSON data and use this variable later in relevant initialize methods.

Is there a better way to do this (without globals)?


Solution 1:

This is how we bootstrap data in a way that it doesn't pollute the global namespace. Instead it uses require.js exclusively. It also helps you provide the initial app configuration based on variables within the template.

Within your rendered page

<script src="require.js"></script>
<script>
define('config', function() {
  return {
    bootstrappedAccounts: <%= @accounts.to_json %>,
    bootstrappedProjects: <%= @projects.to_json(:collaborators => true) %>
  };
});
</script>
<script src="app.js"></script>

globals.js

This file checks for config and extends itself using any of the data returned

define([
  'config',
  'underscore'
], function(config) {

  var globals = {
  };
  _.extend(globals, config);
  return globals;

});

config.js

This file is needed if you want be able to load the app regardless of if you have defined config in the page.

define(function() {
  // empty array for cases where `config` is not defined in-page
  return {};
});

app.js

require([
  'globals',
  'underscore',
  'backbone'
], function(globals) {

  if (globals.bootstrappedAccounts) {
    var accounts = new Backbone.Collection(globals.bootstrappedAccounts);
  }
  if (globals.bootstrappedProjects) {
    var projects = new Backbone.Collection(globals.bootstrappedProjects);
  }

});

Solution 2:

Looks like you can use the require.config() function or the "require" global with the "config" option in order to pass data to a module through the special dependency "module". See http://requirejs.org/docs/api.html#config-moduleconfig:

There is a common need to pass configuration info to a module. That configuration info is usually known as part of the application, and there needs to be a way to pass that down to a module. In RequireJS, that is done with the config option for requirejs.config(). Modules can then read that info by asking for the special dependency "module" and calling module.config().

So, for bootstrapping models we have, in the top level HTML page:

<script>
var require = {
    config: {
        'app': {
            bootstrappedAccounts: <%= @accounts.to_json %>
            bootstrappedProjects: <%= @projects.to_json(:collaborators => true) %>
        }
    }
};
</script>
<script src="scripts/require.js"></script>

Then in the app module (app.js), we have:

define(['module'], function (module) {
    var accounts = new Backbone.Collection( module.config().bootstrappedAccounts );
    var bootstrappedProjects = new Backbone.Collection( module.config().bootstrappedProjects );
});

Here "module" is a special dependency supplied for these types of cases.

This is untested but looks pretty sure from the documentation.

Solution 3:

In RequireJS this is done with the config option for requirejs.config(). Modules can then read that info by asking for the special dependency "module" and calling module.config(). Example:

index.html

<script>
  var require = {
    config: {
      'app': {
        'api_key': '0123456789-abc'
      }
    }
  };
</script>
<script src="js/libs/require.js" data-main="js/main"></script>

main.js

require( ['app'], function(App) {
  new App();
});

app.js

define( ['module'], function(module) {
  var App = function() {
    console.log( 'API Key:', module.config().api_key );
  };

  return App;
});

Just note that the name of the configuration-object must match the name of the module. In my example the name of the module was app, so the name of the configuration-object needed to be named app as well. In the module, you will need to include ['module'] as a dependency and call module.config()[property name] to retrieve the configuration-data.

Read the documentation about this: http://requirejs.org/docs/api.html#config-moduleconfig