Marionette.Toolkit.App

A collection of opinionated Backbone.Marionette extensions for large scale application architecture.


Marionette.Toolkit.App

Marionette.Toolkit.App is an extension of Marionette.Application. Its purpose is to provide an object with a initialize/start/stop/destroy lifecycle. App has several mixins:

  • StateMixin to maintain application state.
  • EventListenersMixin to bind all events to an App while running (and only those) will be remove when stopped.
  • ChildAppsMixin to manage the addition and removal of child Apps and relating the child App lifecycle with the parent App lifecycle.
  • ViewEventsMixin for proxying events from the app’s view to the app.

Documentation Index

Using Toolkit App

Beyond the Toolkit App’s lifecycle, its biggest feature is childApps. This allows children to be tied to the lifecycle of their parent’s lifecycle. As Toolkit App extends Marionette.Application it can be used as a drop-in replacement.

Lifecycle Settings

App’s startAfterInitialized

Call start immediately after initialize if true. Default value is false. Can be added as an option when instantiated or defined on the App definition. It can also be defined as a function returning a boolean value.

const MyApp = App.extend({
  initialize(){
    this.isRunning() === false;
  },
  startAfterInitialized: true
});

const myApp = new MyApp();

myApp.isRunning() === true;

App’s preventDestroy

If set true this App will not be destroyed when its parent App is destroyed. Default value is false. Can be added as an option when instantiated or defined on the App definition. It can also be defined as a function returning a boolean value.

const myApp = new App();

const myChildApp = myApp.addChildApp('myChildApp', {
  AppClass: Marionette.Toolkit.App,
  preventDestroy: false
});

const myPreventDestroyApp = myApp.addChildApp('myPreventDestroyApp', {
  AppClass: App,
  preventDestroy: true
});

myApp.destroy();

// logs true
console.log(myChildApp.isDestroyed());

// logs false
console.log(myPreventDestroyApp.isDestroyed());

App’s startWithParent

If set true this App will start when its parent App starts. Default value is false. Can be added as an option when instantiated or defined on the App definition. It can also be defined as a function returning a boolean value.

const myApp = new App();

const myChildApp = myApp.addChildApp('myChildApp', {
  AppClass: App,
  startWithParent: false
});

const myStartWithParentApp = myApp.addChildApp('myStartWithParentApp', {
  AppClass: App,
  startWithParent: true
});

myApp.start();

// logs false
console.log(myChildApp.isRunning());

// logs true
console.log(myStartWithParentApp.isRunning());

App’s restartWithParent

Default value is null. It can also be defined as a function returning a boolean value.

If restartWithParent is true the child app will stop and start with the parent when restarting. If restartWithParent is false the child app will neither stop nor start with the parent when restarting. If restartWithParent is null the child app will respect startWithParent and stopWithParent when restarting.

const myApp = new App();

const persistantChildApp = myApp.addChildApp('persistantChildApp', {
  AppClass: App,
  restartWithParent: false
});

persistantChildApp.on('stop start', function(options) {
    console.log(this.isRestarting());
});

// does not log
myApp.restart();

const restartingChildApp = myApp.addChildApp('restartingChildApp', {
  AppClass: App,
  restartWithParent: true
});

myApp.start();

restartingChildApp.on('stop start', function(options) {
    console.log(this.isRestarting());
});

// logs true twice
myApp.restart();

App’s stopWithParent

If set true this App will stop when its parent App stops. Default value is true. Can be added as an option when instantiated or defined on the App definition. It can also be defined as a function returning a boolean value.

const myApp = new App();

const myChildApp = myApp.addChildApp('myChildApp', {
  AppClass: App,
  stopWithParent: false
});

const myStopWithParentApp = myApp.addChildApp('myStopWithParentApp', {
  AppClass: App,
  stopWithParent: true
});

myApp.start();
myChildApp.start();
myStopWithParentApp.start();

myApp.stop();

// logs true
console.log(myChildApp.isRunning());

// logs false
console.log(myStopWithParentApp.isRunning());

Lifecycle API

App start

This method sets the App to its running state. Events added after start are registered for removal onStop. This triggers “before:start” / “start” events.

Initial state can be passed as an option to start.

const myApp = new App();

myApp.on('start', function(options){
  console.log('My App Started!');
  options.foo === true;
  this.getState('bar') === 'baz';
});

// false
myApp.isRunning();

const initialState = {
  bar: 'baz'
};

// "My App Started!" logged
myApp.start({
  foo: true,
  state: initialState
});

// true
myApp.isRunning();

// Nothing is logged
myApp.start();

App restart

This method saves the current state of the app before stopping it. It then starts the app again with the preserved state attributes.

const myApp = new App();

myApp.on('before:start', function(options) {
    console.log(options.state);
});

const initialState = {
  foo: 'bar'
};

// logs { foo: 'bar' }
myApp.start({
  state: initialState
});

myApp.setState('foo', 'baz');

// logs { foo: 'baz' }
myApp.restart();

App stop

This method stops the App’s running state. Events added after start are registered for removal onStop. This triggers “before:stop” / “stop” events.

const myApp = new App();

myApp.on('stop', function(options){
  console.log('My App Stopped!');
  options.foo === true;
});

// Nothing is logged
myApp.stop();


myApp.start();

// true
myApp.isRunning();

// "My App Stopped!" logged
myApp.stop({
  foo: true
});

// false
myApp.isRunning();

// Nothing is logged
myApp.stop();

App isRunning

Returns a Boolean indicating whether or not the App is running.

const myApp = new App();

myApp.start();

myApp.isRunning() === true;

myApp.stop();

myApp.isRunning() === false;

App isRestarting

Returns a Boolean indicating whether or not the App is restarting.

const myApp = new App();

myApp.on('before:stop', function(options) {
    console.log(this.isRestarting());
});

myApp.start();

// logs true
myApp.restart();

// logs false
myApp.stop();

App destroy

This method stops the App if running and sets the App’s state to destroyed.

const myApp = new App();

myApp.start();

myApp.isRunning() === true;
myApp.isDestroyed() === false;

myApp.destroy();

myApp.isRunning() === false;
myApp.isDestroyed() === true;

Lifecycle Events

before:start / start events

The “before:start” event and corresponding onBeforeStart method are triggered just before the App isRunning is set true. This is the appropriate place to set up your app’s initial state. Calling setState in onBeforeStart will not trigger any events.

The “start” event and corresponding onStart method are triggered after the App isRunning is set true. Once onStart is run, state event listeners have been applied.

const MyApp = App.extend({
  // ...

  onBeforeStart(options){
    // ...
  },

  onStart(options){
    // ...
  }
});

const myApp = new MyApp({...});

myApp.on('before:start', function(options){
  // ...
});

myApp.on('start', function(options){
  // ...
});

before:stop / stop events

The “before:stop” event and corresponding onBeforeStop method are triggered just before the App isRunning is set false.

The “stop” event and corresponding onStop method are triggered after the App isRunning is set false.

const MyApp = App.extend({
  // ...

  onBeforeStop(options){
    // ...
  },

  onStop(options){
    // ...
  }
});

const myApp = new MyApp({...});

myApp.on('before:stop', function(options){
  // ...
});

myApp.on('stop', function(options){
  // ...
});

App StateModel

A StateModel class can be passed to App instantiation as an option or defined on the App.

const myApp = new MyApp({
  StateModel: MyStateModel
});

App stateEvents

A stateEvents hash can be passed to App instantiation as an option or defined on the App.

const MyApp = App.extend({
  stateEvents: {
    'change': 'onChangeState'
  }
  onChangeState() {
    // Handle state change event
  }
});

Application State

Application state can be passed to App start as a state option. The state is maintained while the app is running.

myApp.start({
  state: {
    limit: 10
  }
});

myApp.getState('limit') === 10;

Application Region

A Marionette.Region instance can be passed to App start as a region option, setting the App region, making it available to both before:start and start events.

myApp.start({
  region: myRegion
});

myApp.getRegion() === myRegion;

App setRegion

Calling setRegion will replace the App’s region making it available to the App’s Region API. Unlike Marionette.Appliation’s region attribute, setRegion only accepts a Region instance.

myApp.setRegion(myView.getRegion('appRegion'));

App getRegion

getRegion performs two functions. When passed no arguments returns the app’s region. You can also give getRegion a region name string which will attempt to return a region from the app’s view. It is sugar for myApp.getView().getRegion('regionName') === myApp.getRegion('regionName');.

const MyApp = Toolkit.App.extend({
  region: '#app-hook'
});

const myView = new Mn.View({
  template: MyTemplate,
  regions: {
    foo: '#foo'
  }
});

myApp.getRegion(); // #app-hook region

myApp.showView(myView);
myApp.getRegion('foo');  // foo region on myView

Application View

A Marionette.Application can have an associated view shown in its region with showView. Toolkit takes this a step further and proxies that view’s showChildView and getChildView. This is simply sugar for common patterns. A View instance can be passed to App start as an option, setting the App view, making it available to both before:start and start events.

myApp.start({
  view: myView
});

myApp.getView() === myView;

App setView

Assign a view to an App. There are two notable use cases for this. First, this allows you to use App.getRegion('regionName') or App.showChildView without first showing the view in the App’s region. This way all of the App’s children can be setup and rendered prior to attaching anything to the DOM.

const MyApp = Toolkit.App.extend({
  onStart() {
    this.setView(myLayoutView);
    this.startChildApp('child', { region: this.getRegion('child') });
    this.showChildView('title', 'My App');
    this.showView();
  }
});

The second is when you want to associate an App with a view already in a region or one that won’t be shown in a region.

const myView = new Mn.View.extend({
  el: $('#existing-dom'),
  regions: {
    foo: '#foo'
  }
});

const myApp = new MyApp();

myApp.start();

myApp.setView(myView);

myApp.getRegion('foo') === myView.getRegion('foo');

setView returns the view.


const myView = myApp.setView(new MyView());

// myApp.listenTo(myView, ...);

App getView

Returns the view instance associated with the App.

myApp.setView(fooView);

myApp.getView() === fooView;

myApp.showView(barView);

myApp.getView() === barView;

myApp.getRegion().show(bazView);

myApp.getView() === bazView;

App showView

Shows a view instance in the App’s region. The first argument for showView is the view instance, but if left undefined the App will attempt to use the current view ie: myApp.getView(). The second argument is region.show options

myApp.showView(myView, { replaceElement: true });


// Alternatively
myApp.setView(fooView);

// Show fooView
myApp.showView();

showView returns the view.


const myView = myApp.showView(new MyView());

// myApp.listenTo(myView, ...);

App showChildView

This method will help when a region from the App’s view is needed.

It has the same API as a Marionette.View’s showChildView and returns the show view.

myApp.showChildView('fooRegion', myChildView, 'fooArg');

//is equivalent to
myApp.getView().getRegion('fooRegion').show(myChildView, 'fooArg');

showChildView returns the child view.


const myView = myApp.showChildView('fooRegion', new MyView());

// myApp.listenTo(myView, ...);

App getChildView

Like showChildView, getChildView is a helper for getting a view shown in a region belonging to the App’s view.

It has the same API as a Marionette.View’s getChildView.

myApp.getChildView('fooRegion');

//is equivalent to
myApp.getView().getRegion('fooRegion').currentView;

View events

View events for an App’s view can be proxied following a very similar API to what you would expect on a Marionette.View and Marionette.CollectionView with their children.

You can use viewEvents, viewTriggers and viewEventPrefix for auto-proxying events.

For more information see the ViewEventsMixin documentation.