How to load loaded models into Backbone.js when using AMD (require.js)

The Backbone.js documentation allows you to load loaded models as follows:

<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 template that cannot be used in AMD's approach (using require.js)

The only possible solution is to declare a global variable that stores JSON data and use this variable later in the appropriate initialization methods.

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

+53
javascript requirejs js-amd
Mar 28 '12 at 21:40
source share
9 answers

This is how we load data so that it does not pollute the global namespace. Instead, it uses require.js exclusively. It will also help you ensure the initial configuration of the application based on the variables inside the template.

Within the displayed 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 validates the configuration and extends itself using any of the returned data.

 define([ 'config', 'underscore' ], function(config) { var globals = { }; _.extend(globals, config); return globals; }); 

config.js

This file is necessary if you want to be able to download the application regardless of if you specified config on 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); } }); 
+71
Apr 23 2018-12-21T00:
source share

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

There is a general need to transfer configuration information to the module. That configuration information is commonly known as part of an application, and there should be a way to pass this up to the module. In RequireJS, this is done with the config option for requirejs.config (). Modules can then read this information by requesting a special module called module, and calling module.config ().

So, for bootstrap models, we have a 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 application 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, the β€œmodule” is a special dependency provided for these types of cases.

This is untested, but it looks pretty convincing from the documentation.

+31
Oct 21 '12 at 0:13
source share

In RequireJS, this is done with the configuration option for requirejs.config() . Then the modules can read this information by requesting a special module "and", 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 remember that the name of the configuration object must match the name of the module. In my example, the module name was app , so the name of the configuration object needed to be called app . In the module, you will need to include ['module'] as a dependency and call module.config()[property name] to get the configuration data.

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

+11
Feb 19 '13 at 20:34
source share

Some of the answers here brought me closer to my similar problem, but nothing nailed it. In particular, the top ranked and accepted answer seemed to give me an unpleasant race condition, where sometimes the original object was loaded first. This also happened in 100% of cases when used with the optimizer. It also uses explicit string names for the module, which usually require documentation from you, is not recommended.

This is how I worked. Like Brave Dave, I use a config object to capture parameters (in my case from the jsp page), for example,

 <script type="text/javascript"> var require = { config: { options : { bootstrappedModels : ${models} } } } </script> 

In particular, note that my parameters are in an object called parameters. This name is optional! Although the documentation does not mention this, the following is an example of how you want to load your configuration (line 564 in requirejs 2.1.1):

 config: function () { return (config.config && config.config[mod.map.id]) || {}; }, 

The key point is that the configuration object must have a property with the mod.map.id key that allows "parameters".

Now you can access these models

 define(['module'], function(module){ console.log(module.config().bootstrappedModels); //... }); 
+6
Oct 31 '12 at 14:32
source share

You can add an end function to the end of your AMD module to check when the init method is defined (so that it can be populated after the body or loaded from include). thus, the module is guaranteed to be available, and initialization can occur when it is ready.

 require(...,function (...) { //define models collections, etc.. var initme = function () { if(document.initThisModule) document.initThisModule(); else setTimeout(initme, 10); }(); }); 
+3
Apr 04 '12 at 9:01
source share

I'm not too familiar with AMD's approach, but instead of using a global variable, why don't you add JSON to dom.

eg:

 var json = ..., $jsonContainer = $(json).wrap("<script id='json-container' type='text/javascript'>").appendTo($("body")); 

Then, instead of the inline script tag suggested by the base documentation, the document is ready:

 $(function(){ MyCollection.reset($("#json-container").html()); ... }); 
+3
Apr 04 2018-12-12T00:
source share

How to do something like this:

 <script> define('Models', ['backbone'], function(Backbone) { var Models = { Accounts: new Backbone.Collection, Projects: new Backbone.Collection }; Models.Accounts.reset(<%= @accounts.to_json %>); Models.Projects.reset(<%= @projects.to_json(:collaborators => true) %>); return Models; }); </script> 

Then you can use Models in other modules, for example:

 var models = require(['Models']); models.Accounts.doWhatYouNeed(); 

or that:

 define(['any', 'dependencies', 'and', 'Models'], function(a, b, c, Models) { // Models will be available here }); 
+2
Mar 29 '12 at 13:50
source share

As described above, a β€œdata module” (or a config, or whatever you want to name) can be included in a file that is already generated in any case (for example, index.html), but I think it's pretty ugly.

Another way would be to declare it in your own module file, but this will require additional transition to the server in production environments. As soon as you want to build and optimize your requirejs dependencies, the data module cannot be included because it is dynamically generated when the page loads.

A third option might be to add it to one of the files you are servicing (for example, the optimized requirejs file), but I don't know how to do it / if it can be done.

+2
Nov 26 '12 at 16:24
source share

Ansewr by @dlrust work, but it is not able to expand the parameter and pass from more than one place in the code. If you try to do something like this in your rendering template:

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

and in another file add some data

 <script> define('config', function() { return { goods: <%= some data %>, showcaseList: <%= some json or array %> }; }); </script> 

It has been overwritten ( DO NOT DISTRIBUT !!! ). In config there will be only the last declared data.

My solution: using the Backbone model with set / get data.

app.js

 define("App", [], function() { window.App = { //  Model: {}, //  Collection: {}, //  View: {}, //  Router: {}, //   Modal: {}, // UI  UI: {} }; return window.App; }); 

global.js

 define(["App", "underscore", "backbone"], function(App, _, Backbone) { "use strict"; //    App.Model.Global = Backbone.Model.extend({ defaults: {} }); return new App.Model.Global; }); 

index.php

 <!DOCTYPE html> <html> <head> <!--HEAD_START--> <script type="text/javascript" data-main="/app/init" src="/app/require/require.js"></script> <!--HEAD_END--> </head> <body> <div id="tm-inner-wrap"> <div id="loader"><i class="uk-icon-refresh uk-icon-spin"></i></div> <!--HEADER_START--> <?= $this->includeTpl('header_view'); ?> <!--HEADER_END--> <!--CONTENT_START--> <div>your html content data</div> <!--CONTENT_END--> <!--FOOTER_START--> <?= $this->includeTpl('footer_view');?> <!--FOOTER_END--> <script> require(["global"], function(Global) { Global.set("notifyList", <?=json_encode($this->notifyList);?>); }); </script> </div> </body> </html> 

another pattern

someTemplate.php

 <div class="tm-inner-body"> <div class="uk-container uk-container-center"> // content data </div> </div> <script> require(["global", "module/index"], function(Global) { Global.set("goodList", <?=json_encode($this->goodList);?>); }); </script> 

index.js

 require(["App", "core", "jquery", "uikit!uikit-addons-min", "underscore", "backbone", "global", "module/good/goodView"], function(App, Core, $, UIkit, _, Backbone, Global, goodView) { "use strict"; // Global.get("notifyList"); its too able App.Collection.Good = new Backbone.Collection(Global.get("showcaseList")["items"]); //    App.View.GoodList = Backbone.View.extend({ //  el: ".tm-good-list", // init initialize: function() { this.collection = App.Collection.Good; //   this.drawList(); }, //   drawList: function() { this.$el.empty(); this.collection.each(function(item, index) { this.$el.append(this.drawItem(item)); }, this); }, //   drawItem: function(data) { var good = new goodView({model: data}); return good.render().el; } }); App.View.Index = Backbone.View.extend({ el: "body", //   events: { // }, // init initialize: function() { var $this = this; if(Global.get("showcaseList")) new App.View.GoodList(); } }); new App.View.Index(); }); 

File structure:

file structure

+1
Nov 10 '16 at 14:13
source share



All Articles