web-dev-qa-db-ja.com

AMD(require.js)の使用中にBackbone.jsでブートストラップされたモデルをロードする方法

Backbone.jsのドキュメントでは、この方法でブートストラップされたモデルをロードすることを推奨しています。

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

しかし、これはAMDアプローチ(require.jsを使用)で使用できないパターンです

唯一可能な解決策は、JSONデータを格納するグローバル変数を宣言し、後でこの変数を関連する初期化メソッドで使用することです。

より良い方法はこれを行うためにありますか(グローバルなし)?

53
opengrid

これは、グローバル名前空間を汚染しないようにデータをbootstrap=する方法です。代わりにrequire.jsを排他的に使用します。また、テンプレート。

レンダリングされたページ内

<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

このファイルは設定をチェックし、返されたデータを使用して自身を拡張します

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

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

});

config.js

このファイルは、ページでconfigを定義したかどうかに関係なくアプリをロードできるようにする場合に必要です。

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
dlrust

Require.config()関数または「config」オプションで「require」グローバルを使用して、特別な依存関係「module」を介してモジュールにデータを渡すことができるようです。 http://requirejs.org/docs/api.html#config-moduleconfig を参照してください:

モジュールに構成情報を渡す一般的な必要性があります。その構成情報は、通常、アプリケーションの一部として知られており、それをモジュールに渡す方法が必要です。 RequireJSでは、requirejs.config()のconfigオプションを使用して行われます。モジュールは、特別な依存関係「モジュール」を要求し、module.config()を呼び出すことにより、その情報を読み取ることができます。

したがって、ブートストラップモデルについては、トップレベルのHTMLページで次のようにします。

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

次に、appモジュール(app.js)に次のものがあります。

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

ここで、「モジュール」は、これらのタイプのケースに提供される特別な依存関係です。

これはテストされていませんが、ドキュメントからかなり確実に見えます。

31
Brave Dave

RequireJSでは、これはrequirejs.config()のc​​onfigオプションで実行されます。モジュールは、特別な依存関係「モジュール」を要求し、module.config()を呼び出すことにより、その情報を読み取ることができます。例:

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

構成オブジェクトの名前はモジュールの名前と一致する必要があることに注意してください。私の例では、モジュールの名前はappであったため、構成オブジェクトの名前もappと命名する必要がありました。モジュールでは、_['module']_を依存関係として含め、module.config()[property name]を呼び出して構成データを取得する必要があります。

これに関するドキュメントを読んでください: http://requirejs.org/docs/api.html#config-moduleconfig

11
Tom Doe

ここでの答えのいくつかは、私に似た問題に近づきましたが、何もそれを釘付けにしませんでした。特に、トップランクで受け入れられた答えは、時々ダミーオブジェクトが最初にロードされるという厄介な競合状態を私に与えたようです。これは、オプティマイザーと一緒に使用した場合にも100%発生しました。また、モジュールの明示的な文字列名も使用しますが、必須のドキュメントでは特にそうしないように勧めています。

ここに私がそれを働いた方法があります。 Brave Daveと同様に、configオブジェクトを使用して(私の場合はjspページから)パラメーターをキャプチャします。

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

特に、私のパラメーターはオプションと呼ばれるオブジェクトにあることに注意してください。 この名前はオプションではありません!ドキュメントではこれについて言及していませんが、以下はrequireがどのように設定を読み込むかを示しています(requirejs 2.1.1の564行目):

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

重要な点は、「オプション」に解決されるキーmod.map.idを持つ設定オブジェクトのプロパティが必要であるということです。

ここから、次のようにモデルにアクセスできます。

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

AMDモジュールの最後にループ関数を追加して、initメソッドが定義されているかどうかを確認できます(これにより、bodyの後に読み込むか、インクルードから読み込むことができます)。そうすれば、モジュールが使用可能であることが保証され、準備ができたときに初期化が行われます。

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

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

私は(あまりにも)AMDのアプローチに精通していませんが、グローバル変数を使用する代わりに、JSONをdomに追加してみませんか。

例えば:

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

次に、バックボーンのドキュメントで提案されている埋め込みスクリプトタグの代わりに、ドキュメント内に準備ができています。

$(function(){
    MyCollection.reset($("#json-container").html());
    ...
});
3
idbentley

このようなことをしてはどうですか:

<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>

次に、次のような他のモジュールでモデルを使用できるようになります。

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

またはこれ:

define(['any', 'dependencies', 'and', 'Models'], function(a, b, c, Models) {
   // Models will be available here
});
2

上記のように、「データモジュール」(または構成、またはそれを呼び出すもの)は、とにかくすでに生成されているファイル(たとえばindex.html)に含めることができますが、これはかなりいと思います。

別の方法は、独自のモジュールファイルで宣言することですが、これには実稼働環境でサーバーへの追加の往復が必要になります。 requirejsの依存関係を構築して最適化するとすぐに、データモジュールはページの読み込み時に動的に生成されるため、インクルードできません。

3番目のオプションは、提供するファイルの1つ(たとえば、最適化されたrequirejsファイル)に追加することかもしれませんが、どのように/どうすればよいのかわかりません。

2
godspeedelbow

@dlrustによるAnsewrは機能しますが、paramを拡張し、コード内の1か所以上から渡すことはできません。レンダリングテンプレートで次のようなことをしようとする場合:

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

別のファイルにデータを追加します

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

上書きされました(NOT EXTEND !!!)。 configでは、最後に宣言されたデータのみになります。

私の解決策:データを設定/取得するBackboneモデルを使用しました。

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>

別のテンプレート

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

1
Vitaliy