Search code examples
javascriptbackbone.jsmarionettebackbone-routing

attaching a view rather than showing it on application startup


I have a Marionette App that is roughly set up in this fashion (irrelevant pieces omitted):

App = new Marionette.Application();

App.addRegions({
  mainRegion: '#main-region'
});

App.AppRouter = Marionette.AppRouter.extend({
  appRoutes: {
    'signin': 'showSignin'
    'about': 'showAbout'
  }
});

var API = {
  showSignin: function () {
    App.Signin.Controller.showSignin();
  },

  showAbout: function () {
    App.Signin.Controller.showAbout();
  }
};

App.addInitializer(function () {
  new App.AppRouter({ controller: API });
});

App.Signin.Controller = {
  showSignin: function () {
    var data = App.request('signin:data'),
        signinView = new SigninView({ model: data });

    App.mainRegion.show(signinView);
  },
  showAbout: function () {
    var aboutView = new AboutView();

    App.mainRegion.show(aboutView);
  }
};

App.SigninView = Marionette.LayoutView.extend({
  template: '#signin-template',
  regions: {
    signinForm: '#signinForm',
    signinForgot: '#signinForgot'
  }
});

App.AboutView = Marionette.AboutView.extend({
  template: '#about-template',
});

$(function () {
  App.start();
});

When the application loads, the page is rendered server-side at first. In that scenario, I want to just call attachView() on the relevant region rather than show() to prevent the unnecessary re-rendering. Then, when the application navigates between two routes, for example from 'about' to 'signin', I would instantiate a new view and pass it to show(). Here's where I'm a little stuck. I could always call attachView() instead of show() when the app starts up by simply passing { silent: true } to Backbone.history.start(). The trick, however, is knowing which page the user has loaded, 'signin' or 'about', so I know which view to attach to mainRegion. This, however, suggests that I shouldn't suppress routes firing when the app loads up so I know which page should have its views attached, but again, this would lead to show() calls. Is there a pattern for solving this problem?


Solution

  • You can use App.mainRegion.hasView() to check whether there is a view in it.

    showAbout: function () {
       var aboutView = new AboutView();
    
       if (App.mainRegion.hasView()) {
           App.mainRegion.show(aboutView);
       } else {
           App.mainRegion.attachView(aboutView);
       }
    }
    

    Another way, you can simply create custom region class with overwritten show logic. Learn more in the marionette docs