States / StateActionManager

As was mentioned on the overview of states page, there are two types of state managers that detect states and run transitions for the matched states. While DisplayStateManager is the one you'll end up using the most, we'll start with the more generic StateActionManger. If you ever end up writing your own state manager, this is the one you're probably going to inherit from or at least look at.

All state declarations that are processed by StateActionManager are prepended by the two array elements - "action", { ...options } - which indicate that what follows next in the this.states array are state declarations to be processed by StateActionManager.

As the name of this state manager suggests, it simply invokes an action whenever a certain state is entered or exited. Action is simply a method defined in the same component class. Method name for the action is passed as a string as the second argument of the state declaration array. However, action can also be a function to be called in place. For example, let's write the following code to alert our users that they're below drinking age using the first approach (passing method name as a string):

class UserComponent extends extend_as("UserComponent").mix(Component).with() {

  constructor() {
    this.attributes = ["age"];
    this.states = [
      "action", {}, // <-- everything that follows after this line will be processed by StateActionManager
      [{ age: { less_than: 18 }}, "alertBelowDrinkingAge"]
    ];
  }

  alertBelowDrinkingAge() {
    alert("You're below the legal drinking age, you can't order alcoholic beverages!");
  }

}

Here, the specified method is an in transition by default. That is, we could've written it as [{ age: { less_than: 18 }}, { in: "alertBelowDrinkingAge" }], but since it is assumed that most of the time it's the in transitions that we're going to use, it made sense to simplify the syntax a little bit. But the same thing can be rewritten so that we use an in-place function which saves us creating a separate method:

class UserComponent extends extend_as("UserComponent").mix(Component).with() {

  constructor() {
    this.attributes = ["age"];
    this.states = [
      "action", {},
      [{ age: { less_than: 18 }}, {
        in: () => alert(
         "You're below the legal drinking age," +
         "you can't order alcoholic beverages!")
      }]
    ];
  }

}

IMPORTANT! We used an object for transitions in the second version of the code, which has they key in with the value of that key being the function to be invoked. In the current version of states implementation, you HAVE to use it like this - simply writing placing a function where the name of the actions where supposed to be wouldn't work. That is, this code won't invoke the function:
this.states = [
  "action", {},
  [{ age: { less_than: 18 }}, () => alert("...")] // <-- WILL NOT WORK!
];

With the out transitions it's pretty much the same, you just have to specify out transitions for the particular state definition:

this.states = [
  "action", {},
  [{ age: { less_than: 18 }}, {
    in:  () => alert("You're below the legal drinking age, you can't order alcoholic beverages!"),
    out: () => alert("Congrats, you're now over the legal drinking age and can order alcoholic beverages!"),
  }]
];

Each in and out transition can consist of several actions passed as an array, for example:

this.states = [
  "action", {},
  [{ age: { less_than: 18 }}, {
    in:  [() => console.log("..."), () => alert("...")],
    out: "alertOverDrinkingAgeToConsole,alertOverDrinkingAgeAsModalWindow"
  }]
];

For the in transition we used an array with two functions as its elements, but for the out transition we passed method names as one string and separated them with a comma within that string. That's possible because StateManager core class functionality takes care of that and treats strings with commas in them as something it needs to split into an array of strings. We could've written it as out: ["alertOverDrinkingAgeToConsole", "alertOverDrinkingAgeAsModalWindow"] to much the same effect.