Implementing StateManager


#1

Hello friends,

I’m working on an application Ember.js latest version (1.0.0) and I would like to implement StateManager but I can not find updated documentation. I’ve never worked with StateManager, you help me with some documentation or explaining some concepts?, How it works StateManager in Ember.js?, What are the layers involved in the changes of state?, What is the relationship between StateManager and Router?

Thanks


#2

@Makis Ember’s state machine has been moved into a separate project: https://github.com/emberjs/ember-states

Over time the state machine had become bloated by trying to serve the needs of the router, views, and Ember-Data. Moving it to a new home gives the code a chance to be bettered without tight coupling to the rest of Ember.

The Ember router no longer uses a Ember.StateMachine.


#3

As @mixonic said the states manager has been moved to an external project. The ember router is for all intents a state machine that governs the states you are in as you move through an ember app.

If you have a specific need to build your own custom state machine just download and use the project source and include it in your project after ember.js include. Ember heavily encourages using the router to manage the state of your application. But if you have a use case where you want to have an embedded state machine and don’t want to use the router itself, that is certainly possible. But you will have to bootstrap and define all the states and transitions yourself.

If you read the source code there is relatively up to date documentation and some code examples embedded in the source. I know because I helped reviewed that as part of the documentation edit back in August.

If you have specific questions let me know, I might be able to help with a JSBin example. Have to first understand the specific case though.

Think of the statemanger as the thing that orchestrates the states and implements the logic that allows one state to transition to another. States themselves are just simple objects that are created and you move from state to state.

Here is a generic example of a StateManager from the docs in the source. There is a lot more like this in the source. Definitely look at the source for more. There is a lot of good info there. And the source is not that large so it possible to sit down and understand most of it fairly quickly. Actually the state and state manager are quite beautiful pieces of code. Fairly elegant in their design.

  var robotManager = Ember.StateManager.create({
    initialState: 'poweredDown',
    poweredDown: Ember.State.create({
      exit: function(stateManager) {
        console.log("exiting the poweredDown state")
      }
    }),
    poweredUp: Ember.State.create({
      enter: function(stateManager) {
        console.log("entering the poweredUp state. Destroy all humans.")
      }
    })
  });

  robotManager.get('currentState.name'); // 'poweredDown'
  robotManager.transitionTo('poweredUp');
  // will log
  // 'exiting the poweredDown state'
  // 'entering the poweredUp state. Destroy all humans.'
  robotManager.transitionTo('poweredUp'); // no logging, no state change

  robotManager.transitionTo('someUnknownState'); // silently fails
  robotManager.get('currentState.name'); // 'poweredUp'

here is an even more simplified example that models the states that a door can be in.

  doorStateManager = Ember.StateManager.create({
    locked: Ember.State.create(),
    closed: Ember.State.create(),
    unlocked: Ember.State.create(),
    open: Ember.State.create()
  });

It is up to you to determine the allowable transitions, for example a locked door cannot be open. And a open door cannot be locked. etc…

It is definitely useful to think of a state machine in the abstract in terms of transitions and allowed and disallowed movements between states.

Hope that helps.


#4

Thanks for your answers. I will explain what I do.

I understand that Ember Router handles states at url level but I need to handle specific states on a same template without changing the route.

My application contains a finder where their results can be edited, deleted, related, etc… and what I want is to handle with StateManager all these possible actions. For example, when I click the search button I want the application state change to “searching” and when finished the search returns to initial state. I also want to only be able to start a search when in the correct state, if I’m editing or deleting results I can not start a search.

Now I use Ember route and want to integrate a StateManager. Can live both instances together? I do not know the layer to make the call to change state in StateManager. The view calls the StateManager and state in the StateManager calls a controller method… or am I wrong?

I hope you understand me, thanks for your help.


#5

@Makis

You might also want to consider creating a “search box” component. You can encapsulate all the state logic inside this component. Very well isolated from the rest of the system and easy to think about once you have it setup.

You can even pass in a state property to this component if necessary from the external system.

The component can speak to the outside world via structured events through the sendAction method. You can even create multiple instances of this component and it can become a highly reusable widget within your UI.

Here are some JSBins to illustrate a possible implementation.

http://jsbin.com/URuSIWO/2/

http://jsbin.com/URuSIWO/3

http://jsbin.com/URuSIWO/4/

Here is a gist from the final example

Note that the above examples contain multiple instances of the search box and they each trigger a different search path.

In the second and third example I bind the state of the controller to a variable in the route and then in the controller

How you implement the “state machine” inside the component doesn’t really matter. That is an internal implementation detail for the component. The outside world have a narrow interface to this component. In fact you could get very far with this component without even creating a formal state machine. Just have flags inside it that let the search box be shown or hidden. It is important to remember that Ember has rich support for bindings and state of view can be long lived.

I think once understood components are a very very powerful tool within ember.

Hopefully this is a useful example.

Also, there was a recent great presentation on the use of components and composable UI patterns by Steven Kane. Well worth the watch. Has a lot of great ideas and useful ways to think about components.

http://w10b.com/#/


#6

Thanks for your help, I think this will be very useful to me. I’ll check all the information and tell you how it goes.


#7

Hi @eccegordo, thanks for all the info here.

I know this is an old thread, but I have need of a state manager in my current app. I’m writing an Ember app that’s connecting to a node backend over websocket. The node app manages file transfers, and reports events to the Ember app - things like transfer:begin, transfer:progress, transfer:error, disk:add, etc. I’ve been using computed properties to determine state so far, but it’s becoming a bit unwieldy.

Would you still recommend using StateManager for something like this?


#8

It is a good question. I think the state machine is probably still serviceable if you just want to use that project. I suspect you might have to think carefully about how you deal with, resolve and wait for promises. So there is likely some syntax overhead there making sure that you are using the RSVP primitives. My understanding is that the Ember router handles most of this for you automagically. So just something to consider, be aware of where your behavior is synchronous and where it is asynchonous.

But certainly if you need to be very deterministic about the transitions and are wanting to do this stuff outside of the normal ember router/route semantics, the state manager seems reasonable. It isn’t a lot of code.

You might have to fiddle with getting it ES6ified if you are using it within something like Ember CLI. I am not sure how maintained it is compared to the rest of the Ember stack which went through the ES6ification awhile back. You might have to experiment with wrapping it in some export statements in your project.