RoundingWellOS/marionette.toolkit

View on GitHub
docs/mixins/child-apps.md

Summary

Maintainability
Test Coverage
# ChildAppsMixin

`ChildAppsMixin` is a private mixin for [`App`](./../app.md). It adds functionality to add or remove child Apps to a parent App and connects the child App lifecycle with the parent App lifecycle.

## Documentation Index
* [ChildAppsMixin's Lifecycle Settings](#childappsmixins-lifecycle-settings)
* [ChildAppsMixin's `childApps`](#apps-childapps)
  * [`regionName` option](#regionname-option)
  * [`getOptions` option](#getoptions-option)
* [ChildAppsMixin API](#childappsmixin-api)
  * [ChildAppsMixin `buildApp`](#childappsmixin-buildapp)
  * [ChildAppsMixin `addChildApp`](#childappsmixin-addchildapp)
  * [ChildAppsMixin `addChildApps`](#childappsmixin-addchildapps)
  * [ChildAppsMixin `getName`](#childappsmixin-getname)
  * [ChildAppsMixin `getChildApp`](#childappsmixin-getchildapp)
  * [ChildAppsMixin `getChildApps`](#childappsmixin-getchildapps)
  * [ChildAppsMixin `removeChildApp`](#childappsmixin-removechildapp)
  * [ChildAppsMixin `removeChildApps`](#childappsmixin-removechildapps)
  * [ChildAppsMixin `startChildApp`](#childappsmixin-startChildApp)
  * [ChildAppsMixin `stopChildApp`](#childappsmixin-stopChildApp)

## ChildAppsMixin's Lifecycle Settings

`childApp` lifecycles may be determined by the settings applied to a `childApp` itself.  For more information read [App Lifecycle Settings](../app.md#lifecycle-settings)

### App's `childApps`
`childApps` is an object literal or a function that returns an object literal.
The object literal must contain app names as keys and app definitions as values.
`childApps` can be passed to an `App` at instantiation or defined on the definition.
If defined as a function it will receive the `options` passed to the `constructor`.

```js
const MyApp = App.extend({
  childApps: function(options){
    return {
      childName: MyChildApp,
      otherName: {
        AppClass: MyOtherApp,
        preventDestroy: true,
        fooOption: 'bar'
      }
    };
  }
});
```

```js
const myApp = new App({
  childApps: {
    childName: MyChildApp,
    otherName: {
      AppClass: MyOtherApp,
      preventDestroy: true,
      fooOption: 'bar'
    }
  }
});
```

### `regionName` option

If a `regionName` is passed along with an app configuration, when the app starts
the region of that name will be passed to the child app from the app's view.

```js
const myApp = new App({
  childApps: {
    childName:  {
      AppClass: MyChildApp,
      regionName: 'bar'
    }
  }
});

const LayoutView = Marionette.View.extend({
  template: _.template('<div id="barRegion"></div>'),
  regions: { bar: '#barRegion' }
});

myApp.setView(new LayoutView());

const childApp = myApp.startChildApp('childName');

myApp.getRegion('bar') === childApp.getRegion(); // true
```

### `getOptions` option

If `getOptions` is defined with the app configuration, it will loop through the `getOptions` array,
using `getOption` on the parent app and passing the result to the child app when starting.

```js
const myApp = new App({
  childApps: {
    childName:  {
      AppClass: MyChildApp,
      getOptions: ['foo', 'bar']
    }
  },
  foo: 'foo'
});
myApp.bar = 'bar';

const childApp = myApp.startChildApp('childName', { bar: 'bar2', baz: 'baz' });

childApp.getOption('foo'); // "foo"
childApp.getOption('bar'); // "bar2"
childApp.getOption('baz'); // "baz"
```

## ChildAppsMixin API

### ChildAppsMixin `buildApp`
Child instances are built through this function.
Override it if a parent app has additional concerns when building its children.

```js
buildApp: function(AppClass, options) {
  return new AppClass(options);
}
```

### ChildAppsMixin `addChildApp`

`App`s can be added as children of an `App` individually using
the `addChildApp` method. This method takes three parameters: the app name,
the app definition and options to pass to the app when built.
The returned value is the add childApp instance.

```js
const myApp = new App();

const myChildApp = myApp.addChildApp('foo', App, { fooOption: true });

myChildApp.getOption('fooOption'); // => true
```

In this example, a child app named "foo" will be added
to the myApp instance.

There are a lot of other ways to define an app,
including object literals with various options and
a function returning an object literal. For more information
on this, see [App's `childApps`](#apps-childapps).

### ChildAppsMixin `addChildApps`

`App`s can also be added en-masse through the use
of the `addChildApps` method. This method takes an object
literal or a function that returns an object literal.
The object literal must contain app names as keys
and app definitions as values.

```js
const ChildAppsMixin = new App();

// With an object literal
myApp.addChildApps({
  main: App,
  navigation: {
    fooOption: true,
    startWithParent: true,
    AppClass: MyNavApp
  }
});

// With a function
myApp.addChildApps(function() {
  return {
    footer: App
  };
});

myApp.getChildApp('main');        //=> 'main' app instance
const navApp = myApp.getChildApp('navigation');  //=> 'navigation' app instance
navApp.getOption('fooOption'); //=> true
myApp.getChildApp('footer'); //=> 'footer' app instance
```

### ChildAppsMixin `getName`

An App's name can be retrieved from the App
instance calling the `getName` method on the
instance. If the app is a childApp then the
app name will be returned, however if an app
is not a childApp or is a parentApp `undefined`
will be returned.

```js
const myApp = new App();

myApp.addChildApp('bar', App);
const barAppName = myApp.getChildApp('bar').getName();

// logs bar
console.log(barAppName);

const myAppName = myApp.getName();

// logs undefined
console.log(myAppName);
```

### ChildAppsMixin `getChildApp`

A childApp instance can be retrieved from the
App instance using the `getChildApp` method and
passing in the name of the childApp.

```js
const myApp = new App();
myApp.addChildApp('foo', App);

const fooApp = myApp.getChildApp('foo');
```

### ChildAppsMixin `getChildApps`

Get all the childApps from the app.
Returns an object literal with named childApps
as attributes.

```js
const myApp = new App();
myApp.addChildApp('foo', App);
myApp.addChildApp('bar', App);

const childApps = myApp.getChildApps();

childApps.foo; //=> foo childApp
childApps.bar; //=> bar childApp
```

### ChildAppsMixin `removeChildApp`

An app can be removed by calling the `removeChildApp`
method and passing in the name of the app.

```js
const myApp = new App();
myApp.addChildApp('foo', App);

myApp.addChildApp('bar', {
  AppClass: App,
  preventDestroy: true
});

const fooApp = myApp.removeChildApp('foo');

const barApp = myApp.removeChildApp('bar');

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

// logs false
console.log(barApp.isDestroyed());
```

The removed app is destroyed unless that app has its
[preventDestroy](../app.md#apps-preventdestroy) setting set to true.

### ChildAppsMixin `removeChildApps`

You can quickly remove all childApps from an
App instance by calling the `removeChildApps`
method.

```js
const myApp = new App();
myApp.addChildApps({
  foo: App,
  bar: App,
  baz: App
});

myApp.removeChildApps();
```

This will destroy all childApps (that don't have preventDestroy set to true), and remove them.

### ChildAppsMixin `startChildApp`

You can quickly start a specific childApp from an
App instance by calling the `startChildApp`
method and passing the childApp name and any options.

```js
const childApps = {
   cA1: App.extend({
     onStart(options) {
       this.mergeOptions(options, ['foo']);
     }
   })
};

const myApp = new App({ childApps: childApps });

// Once you have the childApp instance stored, you can also do childAppInstance.start();
const childAppInstance = myApp.startChildApp('cA1', { foo: 'bar' });

// true
console.log(childAppInstance.isRunning());

// bar
console.log(childAppInstance.getOption('foo'));
```

Note: The parentApp instance is returned for chaining.

### ChildAppsMixin `stopChildApp`

You can quickly stop a specific childApp from an
App instance by calling the `stopChildApp`
method and passing the childApp name.

```js
const myApp = new App({ childApps: { cA1: App } });

const childAppInstance = myApp.startChildApp('cA1');

// true
console.log(childAppInstance.isRunning());

// This is equivalent to childAppInstance.stop();
myApp.stopChildApp('cA1', { foo: 'bar' });

// false
console.log(childAppInstance.isRunning());

// bar
console.log(childAppInstance.getOption('foo'));
```

Note: The parentApp instance is returned for chaining.