<commit_before>marionette.state
================

One-way state architecture for a Marionette.js app.

## Installation

```
npm install marionette.state
bower install marionette-state
git clone git://github.com/Squareknot/marionette.state.git
```

## Documentation

- [Reasoning](#reasoning)
- [Examples](#examples)
  - [Interactive View](#interactive-view)
  - [View Directly Dependent upon Application State](#view-directly-dependent-upon-application-state)
  - [View Indirectly Dependent upon Application State](#view-indirectly-dependent-upon-application-state)
  - [Sub-Applications](#sub-application)
  - [Sub-Views](#sub-views)
- [State API](#state-api)
  - [Class Properties](#class-properties)
  - [Initialization Options](#initialization-options)
  - [Methods](#methods)
- [State Functions API](#state-functions-api)

## Reasoning

A Marionette View is a DOM representation of a Backbone model. When the model updates, so does the view.  Here is a quick example:

```js
// Region to attach views
var region = new Mn.Region({ el: '#region' });

// Model synced with '/rest-endpoint'
var model = new Backbone.Model({ url: '/rest-endpoint' });

// View will re-render when the model changes
var View = Mn.ItemView({
  modelEvents: {
    'change': 'render'
  }
});

// Create the view
var view = new View({ model: model });

// Fetch the latest data
model.fetch().done(function () {
  // Show the view with initial data
  region.show(view);
});

// Updating the model later will cause the view to re-render.
model.fetch();
```

This is great for views that are only interested in representing simple content.  Consider more complex, yet quite common, scenarios:

* **A view renders core content but also reacts to user interaction.**  E.g., a view renders a list of people, but the end user is able to select individal items with a "highlight" effect before saving changes.
* **A view renders core content but also depends on external state.**  E.g., a view renders a person's profile, but if the profile belongs to the authenticated user then enable "edit" features.
* **Multiple views share a core content model but each have unique view states.**  E.g., multiple views render a user profile object, but in completely different ways that require unique view states: an avatar beside a comment, a short bio available when hovering over an avatar, a full user profile display.

Common solutions:

* Store view states in the core content model, but override `toJSON` to avoid sending those attributes to the server.
* Store view states in the core content model shared between views, but avoid naming collisions or other confusion (which view is "enabled"?).
* Store view states directly on the view object and follow each "set" with "if different" statements so you know when a state has changed.

Each of these solutions works up until a point, but side effects mount as complexity rises: Logic-heavy views, views unreliably reflecting state changes, models doing too much leading to excessive re-renders, accidentally transmitting state data to server on save.

Separating state into its own entity and then maintaining that entity with one-way data binding solves each of these problems without the side effects of other solutions.  It is a pattern simple enough to implement using pure Marionette code, but this library seeks to simplify the implementation further by providing a state toolset.

`Mn.State` allows a view to _seamlessly depend on any source of state_ while keeping state logic self-contained and eliminates the temptation to pollute core content models with view-specific state.  Best of all, `Mn.State` does this by providing declarative and expressive tools rather than over-engineering for every use case, much like the Marionette library itself.

## Examples

In each of these examples, views are demonstrated without core content models for simplicity.  This emphasizes that state management is occurring independently from renderable core content.  Adding core content models should be familiar to any Marionette developer.

### Interactive View

From time to time, a view needs to support interactions that only affect itself.  On refresh, these states are reset.  The temptation is to use properties directly on the view instance, but this breaks the Backbone convention that 100% of DOM changes should be rooted in a model change.  In this example, a transient view spawns it own, also transient, State.

State flow for a simple interactive view:

1. A view is rendered with some initial state.
2. The user interacts with the view, triggering a state change.
3. The view reacts by updating the DOM according to the new state.

Solved with Mn.State:

<img src="https://docs.google.com/drawings/d/1MM7iAEzqIMYNvmasTfoO2uwR3TD9oaxuVwUKDslI8mo/pub?w=916&amp;h=269" width=640>

1. A view renders initial state.
2. The view triggers events that are handled by view state.
3. View state reacts to view events, changing its attributes.
4. The view reacts to state changes, updating the DOM.

```js
// Listens to view events and updates view state attributes.
var ToggleState = Mn.State.extend({
  defaultState: {
    active: false
  },

  componentEvents: {
    'toggle': 'onToggle'
  },

  onToggle: function () {
    var active = this.get('active');
    this.set('active', !active);
  }
});

// A toggle button that is alternately "active" or not.
var ToggleView = Mn.ItemView({
  template: 'Toggle Me',
  tagName: 'button',

  triggers: {
    'click .js-toggle': 'toggle'
  },

  stateEvents: {
    'change:active': 'onChangeActive'
  },

  // Create and sync with my own State.
  initialize() {
    this.state = new ToggleState({ component: this });
    Mn.State.syncEntityEvents(this, this.state, this.stateEvents, 'render');
  },

  // Active class will be added/removed on render and on 'active' change.
  onChangeActive(state, active) {
    if (active) {
      this.$el.addClass('is-active');
    } else {
      this.$el.removeClass('is-active');
    }
  }
});

// App controller shows the ToggleView.
var AppController = Mn.Object.extend({
  initialize(options={}) {
    this.region = options.region;
  },

  // Show the ToggleView
  show() {
    // Transient view with its own transient state
    var view = new ToggleView();
    this.region.show(view);
  }
});

var appRegion = new Region({ el: '#app-region' });
var appController = new AppController({
  region: appRegion
});
appController.show();
```

### View Directly Dependent upon Application State<commit_msg>Doc update<commit_after>marionette.state
================

One-way state architecture for a Marionette.js app.

## Installation

```
npm install marionette.state
bower install marionette-state
git clone git://github.com/Squareknot/marionette.state.git
```

## Documentation

- [Reasoning](#reasoning)
- [Examples](#examples)
  - [Stateful View](#stateful-view)
  - [View Directly Dependent upon Application State](#view-directly-dependent-upon-application-state)
  - [View Indirectly Dependent upon Application State](#view-indirectly-dependent-upon-application-state)
  - [View Indirectly Dependent upon Application State with Business Service](#view-indirectly-dependent-upon-application-state-with-business-service)
  - [Sub-Applications](#sub-applications)
  - [Sub-Views](#sub-views)
- [State API](#state-api)
  - [Class Properties](#class-properties)
  - [Initialization Options](#initialization-options)
  - [Methods](#methods)
- [State Functions API](#state-functions-api)

## Reasoning

A Marionette View is a DOM representation of a Backbone model. When the model updates, so does the view.  Here is a quick example:

```js
// Region to attach views
var region = new Mn.Region({ el: '#region' });

// Model synced with '/rest-endpoint'
var model = new Backbone.Model({ url: '/rest-endpoint' });

// View will re-render when the model changes
var View = Mn.ItemView({
  modelEvents: {
    'change': 'render'
  }
});

// Create the view
var view = new View({ model: model });

// Fetch the latest data
model.fetch().done(function () {
  // Show the view with initial data
  region.show(view);
});

// Updating the model later will cause the view to re-render.
model.fetch();
```

This is great for views that are only interested in representing simple content.  Consider more complex, yet quite common, scenarios:

* **A view renders core content but also reacts to user interaction.**  E.g., a view renders a list of people, but the end user is able to select individal items with a "highlight" effect before saving changes.
* **A view renders core content but also depends on external state.**  E.g., a view renders a person's profile, but if the profile belongs to the authenticated user then enable "edit" features.
* **Multiple views share a core content model but each have unique view states.**  E.g., multiple views render a user profile object, but in completely different ways that require unique view states: an avatar beside a comment, a short bio available when hovering over an avatar, a full user profile display.

Common solutions:

* Store view states in the core content model, but override `toJSON` to avoid sending those attributes to the server.
* Store view states in the core content model shared between views, but avoid naming collisions or other confusion (which view is "enabled"?).
* Store view states directly on the view object and follow each "set" with "if different" statements so you know when a state has changed.

Each of these solutions works up until a point, but side effects mount as complexity rises: Logic-heavy views, views unreliably reflecting state changes, models doing too much leading to excessive re-renders, accidentally transmitting state data to server on save.

Separating state into its own entity and then maintaining that entity with one-way data binding solves each of these problems without the side effects of other solutions.  It is a pattern simple enough to implement using pure Marionette code, but this library seeks to simplify the implementation further by providing a state toolset.

`Mn.State` allows a view to _seamlessly depend on any source of state_ while keeping state logic self-contained and eliminates the temptation to pollute core content models with view-specific state.  Best of all, `Mn.State` does this by providing declarative and expressive tools rather than over-engineering for every use case, much like the Marionette library itself.

## Examples

In each of these examples, views are demonstrated without core content models for simplicity.  This emphasizes that state management is occurring independently from renderable core content.  Adding core content models should be familiar to any Marionette developer.

### Stateful View

From time to time, a view needs to support interactions that only affect itself.  On refresh, these states are reset.  In this example, a transient view spawns it own, also transient, State.

State flow for a simple interactive view:

1. A view is rendered with some initial state.
2. The user interacts with the view, triggering a state change.
3. The view reacts by updating the DOM according to the new state.

Solved with Mn.State:

<img src="https://docs.google.com/drawings/d/1MM7iAEzqIMYNvmasTfoO2uwR3TD9oaxuVwUKDslI8mo/pub?w=916&amp;h=269" width=640>

1. A view renders initial state.
2. The view triggers events that are handled by view state.
3. View state reacts to view events, changing its attributes.
4. The view reacts to state changes, updating the DOM.

```js
// Listens to view events and updates view state attributes.
var ToggleState = Mn.State.extend({
  defaultState: {
    active: false
  },

  componentEvents: {
    'toggle': 'onToggle'
  },

  onToggle: function () {
    var active = this.get('active');
    this.set('active', !active);
  }
});

// A toggle button that is alternately "active" or not.
var ToggleView = Mn.ItemView({
  template: 'Toggle Me',
  tagName: 'button',

  triggers: {
    'click .js-toggle': 'toggle'
  },

  stateEvents: {
    'change:active': 'onChangeActive'
  },

  // Create and sync with my own State.
  initialize() {
    this.state = new ToggleState({ component: this });
    Mn.State.syncEntityEvents(this, this.state, this.stateEvents, 'render');
  },

  // Active class will be added/removed on render and on 'active' change.
  onChangeActive(state, active) {
    if (active) {
      this.$el.addClass('is-active');
    } else {
      this.$el.removeClass('is-active');
    }
  }
});

var appRegion = new Region({ el: '#app-region' });
var toggleView = new ToggleView();
appRegion.show(toggleView);
```

### View Directly Dependent upon Application State
{'fraction_non_alphanumeric': 0.09263357571925387, 'fraction_numerical': 0.003714827695226051, 'mean_word_length': 4.13931762794476, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5461697', 'n_tokens_mistral': 3514, 'n_tokens_neox': 3334, 'n_words': 1557}