web-dev-qa-db-ja.com

Backbone.jsルーターを使用して、require.jsでモジュール化されたビューをナビゲートする

私はビューとルーターをrequireで別々のファイルに分けています。次に、ルーターをインスタンス化し、デフォルトビューをレンダリングするmain.jsファイルを作成します。

ルーターには、ルートとしてビュー( 'View /:id')および編集( 'Edit /:id')があります。 main.jsでは、ルーターをインスタンス化するときにrouter.navigate( 'View/1'、true)をハードコーディングでき、ナビゲーションは正常に機能します。ビューファイルで、編集リンクをクリックすると、router.navigate( 'View /' + id、true)を呼び出したいのですが、どうすればいいのかわかりません。

Backbone.history.navigate( 'View /' + id、true)の呼び出しに成功しましたが、グローバルBackboneオブジェクトに依存する必要があるとは思いません。

This.options.router.navigate()を使用できるように({router:appRouter})をビューに渡そうとしましたが、それはうまくいきませんでした。

好奇心が強い場合のために、ここに私のアプリからのコードの束があります:

ルーター:

define(['./View', './Edit'], function (View, Edit) {
    return Backbone.Router.extend({
        routes: {
            'View/:id': 'view',
            'Edit/:id': 'edit'
        },

        view: function (id) {
            var model = this.collection.get(id);
            var view = new View({ model: model });
            view.render();
        },

        edit: function (id) {
            var model = this.collection.get(id);
            var edit = new Edit({ model: model });
            edit.render();
        }
    });
});

見る:

define(function () {
    return Backbone.View.extend({
        template: Handlebars.compile($('#template').html()),

        events: {
            'click .edit': 'edit'
        },

        render: function () {
            //Create and insert the cover letter view
            $(this.el).html(this.template(this.model.toJSON()));
            $('#View').html(this.el);

            return this;
        },

        edit: function () {
            Backbone.history.navigate('Edit/' + this.model.id, true); 
        },
    });
});
35
MrGrigg

ほとんどのバックボーンの質問と同様に、これを処理する方法はたくさんあります。現在のプロジェクトで私がアプローチした方法は、すべてをグローバルなカスタム名前空間に配置し、それを使用して必要な参照を渡すことでした。

_var MyNamespace = {};

MyNamespace.init = function() {
    MyNamespace.appView = new MyAppView();
    MyNamespace.router = new MyRouter();
    // etc
}
_

ビューは、必要に応じて_MyNamespace.router_を参照できます。しかし、これはrequire.jsでは機能しない/推奨されていないようですので、他のオプションをいくつか示します:

  • ルーターを明示的に呼び出さないでください。代わりに、ルーターがリッスンするグローバル状態オブジェクトを変更してください。これが実際に現在のプロジェクトで私がやったことです-詳細は this response をご覧ください。

  • ルーターをトップレベルのビュー(多くの場合AppViewと呼ばれる)に接続し、グローバルにアクセスできるようにし、AppView.router.navigate()を使用します。

  • 内部でBackbone.history.navigate()を呼び出すnavigateユーティリティ関数を提供する別のモジュールを作成します。これはあなたがやっていることと大した違いはありませんが、少しモジュール化され、常にグローバル参照を使用することを防ぎます。これにより、内部実装を変更することもできます。

20
nrabinowitz

私のように他の誰かがこの問題の解決策を探している場合、私がやったことを投稿しています。ボイラープレートのbackbone.jsを使用している場合、_router.js_にinitialize()関数があります。 initialize()関数を次のように変更しました。

_initialize = function () {
  var app_router;
  app_router = new AppRouter();

  // Extend the View class to include a navigation method goTo
  Backbone.View.goTo = function (loc) {
    app_router.navigate(loc, true);
  };

  Backbone.history.start();
};
_

Backbone.jsの継承の特定のフレーバーにより、これにより、任意のビュー内からMyView.goTo(location);を呼び出すことができます。

32

Window.location.hashを使用して、昔ながらの方法でそれを行うことができます:)

window.location.hash = "Edit/1"

明示的なルートが必要ない場合の代替ソリューションを次に示します。アプリの起動時に、Backbone Eventsを拡張するオブジェクトを作成します

window.EventDispatcher = _.extend({}, Backbone.Events);

その後、アプリのどこでもイベントをリッスンできます

EventDispatcher.bind("mymodel:edit", this.editHandler, this);

また、どこからでもイベントをディスパッチします。以下のdataは、ライドのために送信したいパラメータです。

EventDispatcher.trigger("mymodel:edit", data);
8
kreek

私にとっては、goTo関数を使用したソリューションはわずかな変更で機能しました

 Backbone.View.prototype.goTo = function (loc) {
      appRouter.navigate(loc, true);
    };
5
john

私はこの質問が古いことを知っていますが、なぜルーターを取得するためにrequire.jsを使用しないのか疑問に思っています:

define(['./PathToRouter', ], function (router) {
    return Backbone.View.extend({
        template: Handlebars.compile($('#template').html()),

        events: {
            'click .edit': 'edit'
        },

        render: function () {
            //Create and insert the cover letter view
            $(this.el).html(this.template(this.model.toJSON()));
            $('#View').html(this.el);

            return this;
        },

        edit: function () {
            router.navigate('Edit/' + this.model.id, true);
        }
    });
});
3
Naor

このアプローチはどうですか?バックボーンはその4つのコンポーネントすべてにテンプレートパターンを実装しているため、少しのデザインで、循環参照を行うことなくアプリのルーターを介して各ビューに簡単なナビゲーションメカニズムを提供できます(これは他の同様の投稿で見たものですが、それを避けるようにしてください)。

ルーターコンポーネント、他のルーターの例とそれほど変わらない:

define('Router', ['backbone', ... ],
        function (Backbone, ...) {

            var MyRouter = Backbone.Router.extend({
                routes: {
                    'viewA': 'viewA',
                    'viewB': 'viewB'
                },

                initialize: function () {
                    ...
                };
            },
            viewA: function () {
                ...
            },

            viewB: function () {
                ...
            }
});

return MyRouter;
});

アプリは、ルーターインスタンスを作成し、このインスタンスを渡す最初のビューを起動します。

define('App', ['backbone', ...
], function (Backbone, ...) {

    function initialize() {

        //route creation
        if (!this.routes)
            routes = new Router(this); 
        //backbone history start
        Backbone.history.start();

        //ViewA navigation, bigbang
        if (!this.viewA)
            this.viewA = new ViewA({router: this.routes});
        this.viewA.render();
    }

    return {
        initialize: initialize
    };
});

BaseView、すべてのビューの基本コンストラクター定義、およびナビゲーションメソッド:

define('BaseView', ['jquery', 'underscore',  'backbone', ...
], function ($, _, Backbone, ...) {
    var BaseView;

    BaseView = Backbone.View.extend({
        id: '...',

        constructor: function (options) {
            this.router = options.router;
            this.model = options.model;
            Backbone.View.prototype.constructor.call(this);
        },
        initialize: function () {
            this.template = _.template(tpl);
        },

        events: {

        },
        render: function () {
            $(this.el).html(this.template());

            return this;
        },
        //Provides transparent navigation between views throught the backbonejs
        //route mechanism
        navigate: function(pageId)
        {
            this.router.navigate(pageId, {trigger: true});
        }
    });

    return BaseView;
});

Viewインスタンス。各ビューはバックボーンではなくベースビューから拡張し、ベースの動作を継承します。

define('ViewA', ['jquery', 'underscore',  'backbone', 'BaseView'
], function ($, _, Backbone, BaseView) {
    var ViewA;

    ViewA = BaseView.extend({
        id: '...',

        constructor: function (options) {
            this._super("constructor");
        },

        ...
        foo: function()
        {
            ...

            this.navigate("viewB");
        }
    });

    return ViewA;
});

それは私のために機能し、また他のプロジェクトで再利用することもできます。

2
matiasnj

私にとっては、メインアプリケーションにオブジェクトを追加しました。

define(['jquery','underscore','backbone','views/personView','views/peopleView','views/textView'],function($,_,backbone,PersonView,PeopleView,TitleView){

    var Router = Backbone.Router.extend({
           routes:{
               '':'home',
               'edit/:id':'editPerson',
               'new':'editPerson',
               'delete/:id':'deletePerson'
               }
            })

              var initialize = function(){

                 var router  = new Router();

                 window.app = {
                     router:router
                     }

        router.on('route:home',function(){


    })

            //enable routing using '#'[hashtag] navigation
        Backbone.history.start();

            };

            return {
            initialize:initialize
            };

});

ビュー内でwindows.app.router.navigate({''、trigger:true})と言うことができます。この場合、グローバルスコープが適切なプラクティスであるかどうかはわかりませんが、私にとってはうまくいきました。

1
user1975073

AMDモジュールをルーティングするための新しいソリューションがあります。

RequireJSルーター https://github.com/erikringsmuth/requirejs-router

これは、各ページに移動するときにAMDモジュールを遅延ロードするアプローチを取ります。 Backboneルーターでは、すべてのビューを事前に依存関係として要求する必要があります。これにより、最初のページの読み込み時にすべてのアプリのJavascriptが読み込まれます。 RequireJSルーターは、各ルートに移動するとモジュールを遅延ロードします。

アプリの実行に使用されるmain.jsの例

define([], function() {
  'use strict';

  // Configure require.js paths and shims
  require.config({
    paths: {
      'text': 'bower_components/requirejs-text/text',
      'router': 'bower_components/requirejs-router/router'
    }
  });

  // Load the router and your layout
  require(['router', 'js/layout/layoutView'], function(router, LayoutView) {
    var layoutView = new LayoutView();
    // The layout's render method should draw the header, footer, and an empty main-content section
    // then load the content section.
    // render: function() {
    //   this.$el.html(this.template({model: this.model}));
    //   router.loadCurrentRoute();
    // }

    // Configure the router
    router
      .registerRoutes({
        home: {path: '/', moduleId: 'home/homeView'},
        order: {path: '/order', moduleId: 'order/orderView'},
        notFound: {path: '*', moduleId: 'notFound/notFoundView'}
      })
      .on('statechange', function() {
        // Render the layout before loading the current route's module
        layoutView.render.call(layoutView);
      })
      .on('routeload', function(module, routeArguments) {
        // Attach the content view to the layoutView's main-content section
        layoutView.$('#main-content').replaceWith(new module(routeArguments).render().el);
      })
      .init({
        // We're manually calling loadCurrentRoute() from layoutView.render()
        loadCurrentRouteOnStateChange: false
      });
  );
);
0
Erik Ringsmuth