Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Marionette Deep Nested Regions with Routing

We have modularised our marionette application into modules. However now we are at a complete loss on how to handle the different entry points from the router and restore the state in the correct regions.

enter image description here

The problem being the application is top down, the regions are nested inside another region etc etc... (see diagram). What makes this difficult is that the top down is also not a straight line, there are menus in each module that dictate which other module to load below it. We just can't figure out how to pass along a chain of commands or instructions to replicate the state.

Each module has its own layout/region and triggers another module passing as parameter again another region and model.

We essentially acknowledged 3 distinct ways a state can come into place.

  1. IN APP NAVIGATION from the top down using buttons in the app
  2. ROUTER when a url matches
  3. BROWSER HISTORY when using previous/back buttons

some code

@MyApp = do (Backbone, Marionette) ->

  App = new Marionette.Application

  App.addRegions
    mainRegion: "#main"

  model = ...
  App.execute "module:1:load", App.mainRegion, model

## -------------------------------------------------------

@MyApp.module "ModuleOne", (ModuleOne, App, Backbone, Marionette, $, _) ->
  @startWithParent = false

  ## MODULE
  class ModuleOne.Show.Controller extends Marionette.Controller

    initialize: (options) ->
      @layout = @getLayoutView()
      @region = options.region
      @model = options.model

      @listenTo @layout, "show", =>
        @showRegionOne()
        @showRegionTwo()

      @region.show(@layout)

    showRegionTwo: ->
      App.execute "module:2:load", @layout.regionTwo, @model

      ...


  ## API
  API =
    show: (region, model) ->
      new ModuleOne.Show.Controller
        region: region
        model: model

  App.vent.on "module:1:load", (region, model) ->
    API.show region, model


  ## ROUTER
  class ModuleOne.Router extends Marionette.AppRouter
    routes:
      "path1/*subroute" : "pathOne"
    pathOne: (hash) ->
      ## this gets triggered on URL enter if /path1 is in URL
      new App.ModuleTwo.Router("path1")

  App.addInitializer ->
    new ModuleOne.Router

## -------------------------------------------------------

@MyApp.module "ModuleTwo", (ModuleTwo, App, Backbone, Marionette, $, _) ->
  @startWithParent = false

  ## MODULE
  ...

  ## API
  API =
    show: (region, model) ->
      new ModuleTwo.Show.Controller
        region: region
        model: model

  App.vent.on "module:2:load", (region, model) ->
    API.show region, model

  ## ROUTER
  API_ROUTER = 
    pathTwo: ->
      new App.ModuleThree.Router("path1/path2")
  class ModuleTwo.Router extends Marionette.SubRouter
    controller: API_ROUTER
    appRoutes:
      "path2/*subroute" : "pathTwo"

## -------------------------------------------------------

@MyApp.module "ModuleThree", (ModuleThree, App, Backbone, Marionette, $, _) ->
  @startWithParent = false

  ## MODULE

  ## API
  API =
    show: (region, model) ->
      new ModuleThree.Show.Controller
        region: region
        model: model

  App.vent.on "module:3:load", (region, model) ->
    API.show region, model

  ## ROUTER
  API_ROUTER = 
    pathThree: ->
      new App.ModuleFour.Router("path1/path2/path3")
  class ModuleThree.Router extends Marionette.SubRouter
    controller: API_ROUTER
    appRoutes:
      "path3/*subroute" : "pathThree"  

extra notes

We have played with Marionette.SubRouter which allows us to modularize the routes definition in that each module only knows about it's own relative URL and doesn't know what's before it. Currently if the user goes to /path1/path2/path3/path4 we can pick it up and set a trigger hook along the way and in order at path1 path2 path3 path4. The other problem here is then when the user presses forward / backward, we then after only get the end hooks triggered i.e. path3 so we got stuck here again and thought we are doing this wrong.

Should we try to recursively tell it to load from the end of the route backwards to the root module4(path4) > module3(path 3) > module(path 2) > module1(path 1) OR should we figure out a mechanism to instruct each module the paths to take downwards path 1 > path 2 > path 3 > path 4

like image 511
user391986 Avatar asked Oct 20 '22 16:10

user391986


1 Answers

I would suggest parameterized routes. I'm not familiar enough with coffeescript, but here is a JS based example from a webapp I am working on:

ClientsApp.Router = Marionette.AppRouter.extend({
  appRoutes: {
      //...
      "clients/:id/result/:resultID":"showReport",
      //
  }
});

var API = {
  showReport: function(id, resultID){
      ClientsApp.Show.Controller.showReport(id, resultID);
  },
}; 

You can specify the parameters of whatever states drive the later modules, and Marionette knows how to pull the values (with a ':') from the route and pass them into the function. This would solve your rebuilding/passing values down to later views, while preventing the recursion/propagation.

like image 116
mix3d Avatar answered Oct 27 '22 09:10

mix3d