53 votes

Comment charger des modèles bootstrapped dans Backbone.js tout en utilisant AMD (require.js)

La documentation de Backbone.js suggère de charger les modèles bootstrapped de cette manière :

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

Mais c'est un modèle qui ne peut pas être utilisé dans Approche AMD (avec require.js)

La seule solution possible est de déclarer variable globale stockant les données JSON et utiliser cette variable plus tard dans les méthodes d'initialisation pertinentes.

Y a-t-il un meilleur moyen pour faire cela (sans globales) ?

71voto

dlrust Points 1363

C'est ainsi que nous amorçons les données de manière à ce qu'elles ne polluent pas l'espace de noms global. Au lieu de cela, il utilise exclusivement require.js. Il vous aide également à fournir la configuration initiale de l'application en fonction des variables du modèle.

Dans votre page rendue

<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

Ce fichier vérifie la configuration et s'étend en utilisant n'importe laquelle des données retournées

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

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

});

config.js

Ce fichier est nécessaire si vous voulez être en mesure de charger l'application indépendamment du fait que vous ayez défini le fichier config dans la 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);
  }

});

31voto

Brave Dave Points 802

Il semble que vous puissiez utiliser la fonction require.config() ou le global "require" avec l'option "config" afin de transmettre des données à un module via la dépendance spéciale "module". Voir http://requirejs.org/docs/api.html#config-moduleconfig :

Il est souvent nécessaire de transmettre des informations de configuration à un module. Cette configuration sont généralement connues comme faisant partie de l'application, et et il doit y avoir un moyen de les transmettre à un module. Dans RequireJS, cela est fait avec l'option config pour requirejs.config(). Les modules peuvent alors lire ces informations en demandant la dépendance spéciale "module". et en appelant module.config().

Ainsi, pour les modèles d'amorçage, nous avons, dans la page HTML de niveau supérieur :

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

Ensuite, dans le module d'application (app.js), nous avons :

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

Ici, "module" est une dépendance spéciale fournie pour ces types de cas.

Ceci n'est pas testé mais semble assez sûr d'après la documentation.

11voto

Tom Doe Points 227

Dans RequireJS, ceci est fait avec l'option de configuration pour requirejs.config() . Les modules peuvent alors lire cette information en demandant la dépendance spéciale "module" et en appelant module.config() . Exemple :

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;
});

Notez simplement que le nom de l'objet de configuration doit correspondre le nom du module. Dans mon exemple, le nom du module était app le nom de l'objet de configuration devait donc être nommé app également. Dans le module, vous devrez inclure ['module'] comme une dépendance et appeler module.config()[property name] pour récupérer les données de configuration.

Lisez la documentation à ce sujet : http://requirejs.org/docs/api.html#config-moduleconfig

6voto

Ollie Edwards Points 1794

Certaines des réponses données ici m'ont rapproché de mon problème similaire, mais aucune n'a permis de le résoudre. En particulier, la réponse la mieux classée et acceptée semblait me donner une condition de course désagréable où parfois l'objet factice se chargeait en premier. Cela se produisait également 100% du temps lorsqu'il était utilisé avec l'optimiseur. Il utilise également des noms de chaîne explicites pour le module, ce que la documentation requise vous conseille spécifiquement de ne pas faire.

Voici comment j'ai travaillé. Comme Brave Dave, j'utilise l'objet config pour capturer les paramètres (dans mon cas à partir d'une page jsp) comme ceci

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

Notez en particulier que mes paramètres sont dans un objet appelé options. Ce nom n'est pas facultatif ! Bien que la documentation ne le mentionne pas, voici comment require chargera votre configuration (ligne 564 dans requirejs 2.1.1) :

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

Le point clé est qu'il doit y avoir une propriété sur l'objet de configuration avec la clé mod.map.id qui se résout en 'options'.

De là, vous pouvez maintenant accéder aux modèles comme suit

define(['module'], function(module){
    console.log(module.config().bootstrappedModels);
    //...
});

3voto

Justin Alexander Points 800

Vous pourriez ajouter une fonction bouclée à la fin de votre module AMD pour vérifier si la méthode init est définie (afin qu'elle puisse être remplie après le corps, ou chargée à partir d'un include). De cette façon, le module est garanti disponible et l'initialisation peut se produire quand il est prêt.

require(...,function (...) {
   //define models collections, etc..

   var initme = function () {
     if(document.initThisModule) 
       document.initThisModule();
     else
       setTimeout(initme, 10);
   }();
});

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X