Search code examples
javascriptbackbone.jsrequirejsmarionette

Marionette js access to app from controller with requirejs


I want to get access to my main app instance from main controller to render new View. What i want to do is commented in controller/main.js code, as i understand this is circ dependency in require js, but i don't understand how to fix this

 file structure
       - controllers/main.js
       - models/
       - templates/
       - views/
       - app.js
       - main.js
       - router.js

main.js

require.config({...})
require(['app'], function(app) {
    app.initialize().start();
});

app.js

define(['jquery', 'underscore', 'backbone', 'marionette', 'router','controllers/main'],
function($, _, Backbone, Mn, Router, MainController) {

    let app = null;

    const App = Mn.Application.extend({
        region: '#app',
        initialize(options) {
            this.router = options.router;
        },
        onBeforeStart() {
            console.log('before start');
        },
        onStart() {
            Backbone.history.start();
        }
    });

    return {
        get instance() {
            return app;
        },
        initialize() {

            if (!app) {
                const controller = new MainController();
                const router = new Router({controller});
                app = new App({router});
            }
            return this;
        },
        start() {
            this.instance.start();
        },
    }
 });

router.js

define([
    'jquery',
    'underscore',
    'marionette',
], function($, _, Mn) {
    return Mn.AppRouter.extend({
        initialize(options) {
            this.controller = options.controller;
        },
        appRoutes: {
            '': 'index',
            'profile': 'profile',
            '*notFound': 'notFound'
        },
    });
});

controllers/main.js

define(['jquery', 'underscore', 'marionette', 'app'], function($, _, Mn, app) {
    return Mn.Object.extend({
        index() {
            console.log(app); // undefined
            console.log('index method invoked');
             /*
             i want to do like this
             app.showView(new SomeView());
             or this.triggerMethod('render', 'someView') and then listen for this event from app.js like this.router.controller.on('render', handler) and dynamic require somehow... 
             or what is best practice ? iam confused
             */
        },
        profile() {
            console.log('profile method invoked');
        },
        notFound() {
            console.log('notFound method invoked');
        }
    });
});

Solution

  • You can asynchronously load the app inside index method of controller (wherever you need it) rather than adding it as a dependency of module

    define(['jquery', 'underscore', 'backbone', 'marionette', 'router','controllers/main'],
      function($, _, Backbone, Mn, Router, MainController) {
    
        const App = Mn.Application.extend({
          region: '#app',
          initialize(options) {
            this.router = options.router;
          },
          onBeforeStart() {
            console.log('before start');
          },
          onStart() {
            Backbone.history.start();
          }
        });
    
        const controller = new MainController();
        const router = new Router({
          controller
        });
    
        return app = new App({
          router
        });
      });
    
    define(['jquery', 'underscore', 'marionette'], function($, _, Mn) {
      return Mn.Object.extend({
        index() {
          require(['app'],function(app){
            console.log(app);
          });
        },
        profile() {
          console.log('profile method invoked');
        },
        notFound() {
          console.log('notFound method invoked');
        }
      });
    });