Code Monkey home page Code Monkey logo

stativus's People

Contributors

140am avatar ccapndave avatar etgryphon avatar gregwebs avatar joshholt avatar onkis avatar scarney81 avatar ubun2 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

stativus's Issues

Pass arguments to enterState()

Isn't it necessary to allow us passing arguments to enterState() from goToState()?

Eg.

Idle -[:USER_TYPED_SOME_WORDS]-> Translating

Here when user types a word I call this.goToState('translating') from userTypedAWord event handler.

But for this to work I have to pass the words typed in.

Wouldn't this be a good thing to do?

this.goToState('translating', word1, word2 ...)

In this way it works just like this.sendEvent() where you can pass custom arguments.

sendEvent functions from exitState fired AFTER new state is entered?

At first i thought this was a bug, but apparently not.

var app = Stativus.createStatechart()

app.addState('root', {
    initialSubstate: 'sub1',
    clean: function() {
        console.log('clean')
    },
    goToSub2: function() {
        this.goToState('sub2')
    }
})
app.addState('sub1', {
    parentState: 'root',
    enterState: function() {
        var self = this
        setTimeout(function() {
            self.sendEvent('goToSub2')
        }, 2000)
    },
    exitState: function() {
        console.log('exit sub1')
        this.sendEvent('clean')
    }
})
app.addState('sub2', {
    parentState: 'root',
})

Outputs:

ENTER: root stativus-evt-min.js:502
ENTER: sub1 stativus-evt-min.js:502
EVENT: root fires [goToSub2] with 0 argument(s) stativus-evt-min.js:457
exit sub1 app.js:1
EXIT: sub1 stativus-evt-min.js:513
ENTER: sub2 stativus-evt-min.js:502
EVENT: root fires [clean] with 0 argument(s) stativus-evt-min.js:457
clean

Notice exit sub1 is output, then the app leaves the state then the clean function is actually fired after sub2 is already entered??

Can you explain what is going on here, it's likely this is a stupid question, but I expected the event handler to be triggered before the state was exit.

Question: Parallell states shouldn't affect each other?

Here are my states:

application (substatesAreConcurrent: true)
application.routing
application.session (initialSubstate: "checking")
application.session.checking // this.goToState("application.session.loggedout")
application.session.loggedout
application.session.loggedin

The problem is when application.session.checking goes to application.session.loggedout, application.routing is exited. Shouldn't concurrent states be independent of each other?

More detailed logging

When an event is sent but there is no handler for it (using statechart.sendEvent() and not this.sendEvent()), that event is not logged in the console.

Wouldn't it be better if the event is logged, and then log the event handler/s that is handling the event.

Eg.

statechart.sendEvent("showUser", "Foo");

will show this log if no handler is there:

EVENT: "showUser" is fired with 1 argument ["Foo"]

And if there are multiple handlers they will all be logged:

EVENT: "showUser" is fired with 1 argument ["Foo"]
HANDLER: StateB handled the event
HANDLER: StateA handled the event

This would give us more of what is happening so we don't need to console.log() in some places to figure things out.

Feature: Check if state is active

Is there a way to check if a state is active/entered?

At the moment I have to do like this in all my states I test:

enterState: function() { pageOneIsEntered = true },
exitState: function() { pageOneIsEntered = false }

I was hoping that you could do something like:

statechart.isStateActive("PageOne")

// or

var states = statechart.getActiveStates()
// I can now check if a state is in the array.

// or

var states = statechart.getAllStates()
// I can now check if a state's isActive property is set to true.

This would make writing tests simple since you could send some events then just assert that the states are active.

Statechart tutorials

goToHistoryState() is broken...

Using the following code:

/*globals Stativus $*/
var statechart = Stativus.createStatechart();

statechart.addState('state_one', {
  initialSubstate: 'substate_one',
  actions: {
    "#boom click": 'go'
  }
});
statechart.addState('state_two', {
  actions: {
    "#boom click": 'go'
  },
  go: function(evt){
    this.goToHistoryState('state_one'); 
  }
});

statechart.addState('substate_one', {
  parentState: 'state_one',
  go: function(evt){
    this.goToState('substate_two'); 
  }
});

statechart.addState('substate_two', {
  parentState: 'state_one',
  go: function(evt){
    this.goToState('state_two'); 
  }
});

Feature: Nested states

I love the ability to dynamically add states through statechart.addState()

In this way you can have your states in multiple files.

But many times I wanna add one state in the same file that contains other states eg.

Yi.addState("STORE", {
  initialSubstate: "STORE_LOADING"
});
Yi.addState("STORE_LOADING", {
  parentState: "STORE"
});
Yi.addState("STORE_OPENED", {
  parentState: "STORE"
});
  1. One issue is that I am violating the DRY principle. In larger setups when I change the parent state name I have to make a change in all other substates's parentState.
  2. Another issue is that you don't see the hierarchy. You have to study it and draw a correct picture in your head about the nesting. With many states having substates having substates and so on takes a lot of time and you are putting time on something that could come for free and let you be more productive.
  3. Third issue is that you now need a namespace for all generic states like LOADING, READY etc. With nesting you don't have to make up custom namespaces. You could just call them through STORE.LOADING etc.
  4. Forth advantage would be that a lot of frameworks let you do nestings like this already (Sproutcore, ExtJS...). ExtJS allows you to use add() or nest them in "items" key (for views), so this is kinda an usual setup.

It would save a lot of time and look cleaner (less code, better structure and DRY) if you could do:

Yi.addState("STORE", {
  initialSubstate: "LOADING",
  states: [{
    name "LOADING"
  }, {
    name: "READY"
  }]
});

What do you think?

mistakes in quickstart

  1. statechart.addState("#state-two", {
    enterState: function(){
    $('#state-two').show(); // Using JQuery, but you can use whatever...
    },
    exitState: function(){
    $('#state-two').hide(); // Using JQuery, but you can use whatever...
    }
    fireEvent: function(){
    this.goToState('#state-one');
    }
    });

There should be coma like this:

statechart.addState("#state-two", {
enterState: function(){
$('#state-two').show(); // Using JQuery, but you can use whatever...
},
exitState: function(){
$('#state-two').hide(); // Using JQuery, but you can use whatever...
},
fireEvent: function(){
this.goToState('#state-one');
}
});

  1. statechart.sendEvent('firstEvent');
    change to
    statechart.sendEvent('fireEvent');

Feature: addStates()

When I started to use "option 3" for adding states I was making the code more DRY. But what got me even more amazed was that I was creating a statechart blueprint that gives me a great overview over the whole statechart. It's easier to develop, maintain and debug.

The code below is in Coffeescript which makes it makes it even more clean. If you haven't used Coffeescript you can just dump the code in http://js2coffee.org

statechart.addState "MAIN"
  initialSubstate: "MAIN_LOADING"

  enterState: @enterState()

  states: [
    [
      "MAIN_LOADING", mainLoading
      "show": -> @goToState "MAIN_SHOWN"; yes
    ]
    [
      "MAIN_SHOWN", loader, init
      initialSubstate: "VIEW"
      states: [
        [
          "VIEW"
          initialSubstate: "BUY"
          states: [
            [
              "BUY"
              initialSubstate: "BUY_LOADING"
              states: [
                [
                  "BUY_LOADING", buyLoading, loader
                  "show": -> @goToState "BUY_SHOWN"; yes
                  "hide": -> @goToState "BUY_HIDDEN"; yes
                ]
                [
                  "BUY_SHOWN"
                ]
                [
                  "BUY_HIDDEN"
                ]
              ]
            ]
          ]
        ]
      ]
    ]
  ]

The "problem" is that the parent state "Main" doesn't follow the option 3 convention. I think it would be cleaner and consistent if you could write it like this instead:

statechart.addStates [
  "MAIN", main, init
  initialSubstate: "MAIN_LOADING"
  states: [
    [
      "MAIN_LOADING", mainLoading
      "show": -> @goToState "MAIN_SHOWN"; yes
    ]
    [
      "MAIN_SHOWN", loader, init
      initialSubstate: "VIEW"
      states: [
        [
          "VIEW"
          initialSubstate: "BUY"
          states: [
            [
              "BUY"
              initialSubstate: "BUY_LOADING"
              states: [
                [
                  "BUY_LOADING", buyLoading, loader
                  "show": -> @goToState "BUY_SHOWN"; yes
                  "hide": -> @goToState "BUY_HIDDEN"; yes
                ]
                [
                  "BUY_SHOWN"
                ]
                [
                  "BUY_HIDDEN"
                ]
              ]
            ]
          ]
        ]
      ]
    ]
  ]
]

In this way the statechart blueprint has a consistent structure and the parent state will have the same DRY benefits like the others.

hasState()?

A good method for testing purpose is hasState() since now I can only test if a state is entered not if the state is really there in the statechart. Would help to cover up more edge cases.

##### States
class Mood extends Yie.State
class Happy extends Yie.State
class Angry extends Yie.State
class Sad extends Yie.State

##### Statecharts
class Soul extends Yie.Statechart
  init: ->
    @state Mood, ->
      @state Happy, ->
      @state Angry, ->
      @state Sad, ->

##### Statemachines
class Person extends Yie.Statemachine
  statechart: Soul

person = new Person

person.isInState("Mood").should.be.true
person.isInState("Happy").should.be.true
person.isInState("Angry").should.be.false
person.isInState("Sad").should.be.false

What do you think?

BUG: concurrent state's child state is never entered

Hey Evin - I may be missing something, but I've stripped this example as far down as I could and still am able to reproduce this issue. Any thoughts?

var statechart;
if(require) // I'm using node to make this easier to test
  statechart = require('./stativus').createStatechart();
else
  statechart = Stativus.createStatechart();

////////////////////////////////////////////
// MY STATES:
// application
// - page (#nav and #content are concurrent)
//   - page#nav
//     - page#nav#first <-- BUG, NEVER LOADS
//   - page#content
////////////////////////////////////////////

statechart.addState('application', {
});

statechart.addState('page', {
  parentState: 'application'
  , substatesAreConcurrent: true
  , states: [
    {
      name: 'page#nav'
      , enterState: function(){ console.log('nav loaded'); } //<-- fires
      , states:[
        {
          name: 'page#nav#first'
          , enterState: function(){ console.log('nav.1 loaded'); } //<-- never fires
        }
      ]
    },
    {
      name: 'page#content'
      , enterState: function(){ console.log('content loaded'); } //<-- fires
    }
  ]
});

statechart.initStates('page#nav#first');
console.log(statechart.currentState().map(function(state){ return state.name; }));
// the above line should print something like:
//  ['page#nav#first', 'page#nav', 'page#content', 'page', 'application']
// instead, it prints:
//  ['page#nav', 'page#content', 'page', 'application']
// WHERE IS 'page#nav#first' ???

Question: Does parent has to enter a child

I wonder if it's mandatory for a parent to either use:

initialSubstate

OR

substatesAreConcurrent

Is it possible/good practice to not enter a substate/substates and let the parent enter later on when an event occurs?

concurrent sub-states do not EXIT during parent state transition?

Editing this issue again (3rd time) since I either implement concurrent state in a complete wrong way or there is a much bigger issue going on with the way the parent state chart tree is parsed. Example based on https://gist.github.com/1388244:

var sc = Stativus.createStatechart();
sc.addState('StateA1', {
  globalConcurrentState: 'default_states',
  initialSubstate: 'StateA1B1',
  states: [{
      name: 'StateA1B1',
      substatesAreConcurrent: true,
      states: [{
        name: 'StateA1B1-A',
        test: function() {}
      },{
        name: 'StateA1B1-B',
        test: function() {}
      }]
    },
    {
      name: 'StateA1B2',
      initialSubstate: 'StateA1B2-A',
      states: [
        { name: 'StateA1B2-A' },
        { name: 'StateA1B2-B' }
      ]
    }
  ]
});

sc.addState('StateA2', {
  globalConcurrentState: 'modal_states',
  states: [
    { name: 'StateA2B1' },
    { name: 'StateA2B2' }
  ]
});

sc.initStates({'default_states': 'StateA1', 'modal_states': 'StateA2'});

Console

sc.goToState('StateA1B2', 'default_states');
EXIT: StateA1B1
ENTER: StateA1B2
HISTORY STATE: For StateA1 => history state set to: StateA1B2
ENTER: StateA1B2-A
HISTORY STATE: For StateA1B2 => history state set to: StateA1B2-A

Note: No EXIT on 'StateA1B1-A' or 'StateA1B1-B'

sc.goToState('StateA1B1', 'default_states');
EXIT: StateA1B2-A
EXIT: StateA1B2
ENTER: StateA1B1
ENTER: StateA1B1-A
ENTER: StateA1B1-B

..switching back and forth between the two states a few times..

sc.goToState('StateA1B2', 'default_states');
sc.sendEvent('test');

This will fire the test event multiple times (as the states were never exited) even so at this point we are not even in the StateA1B1 state:

EVENT: StateA1B1-B fires [test] with 0 argument(s)
EVENT: StateA1B1-A fires [test] with 0 argument(s)
EVENT: StateA1B1-B fires [test] with 0 argument(s)
EVENT: StateA1B1-A fires [test] with 0 argument(s)
EVENT: StateA1B1-B fires [test] with 0 argument(s)
EVENT: StateA1B1-A fires [test] with 0 argument(s)
EVENT: StateA1B1-B fires [test] with 0 argument(s)
EVENT: StateA1B1-A fires [test] with 0 argument(s)

Thanks in advance for any feedback!

Add behaviors that can be reused across states

Sometimes you might have states where the same thing is happening in the enterState or exitState. Instead of repeating that code everywhere, if you could create a behavior that you just add to the state, it would help keep things DRY.

For example:

statechart.addBehavior('noSearchBar', {
  enterState: function() {
    $('#search').hide();
  },
  exitState: function() {
    $('#search').show();
  }
});

statechart.addState('profile', {
  parentState: 'loggedIn',
  behaviors: ['noSearchBar']
});

statechart.addState('activity', {
  parentState: 'loggedIn',
  behaviors: ['noSearchBar'],
  enterState: function() {
    // other stuff happens here also
  }
});

console.log puts "Undefined"

I downloaded Stativus and did:

require("./stativus");
var statechart = Statechart.create();
statechart.addState("Test")
statechart.initStates("Test")

It seems to work except that the console displayed:

ENTER: undefined

I guess it's just something small going on making it behave like this. Could this be fixed so it's Node.js compatible? Would be good to be able to use it both on backend and frontend. Also for testing purpose it would be faster to run it on server side.

Feature: No parentState and shorter initialSubstate

After a time the state names will have a very long namespace.
If I need to change a namespace, I have to do it in every state name.

me.application.myStatechart.addState("platform.application.sellers", {
parentState: "platform.application",
initialSubstate: "platform.application.sellers.loading"
});

Wouldn't this be better for the eyes?

me.application.myStatechart.addState("platform.application.sellers", {
initialSubstate: "loading"
});

No parentState and namespace for initialSubstate since its implicitly defined in the state name.

Question: Multiple states with substatesAreConcurrent?

Here are my states:

application (substatesAreConcurrent)
application.routing (substatesAreConcurrent)
application.routing.state1
application.routing.state2
application.routing.state3

The problem here is that application.routing isn't entered.

If I have application set to initialSubstate: "application.routing" instead it works.

Should this be the default behavior?

Does it has something to do with globalConcurrentState?

Same name error

When adding states using the advanced layout I get an error when the some substates have identical name.

Eg. I have "loggedIn" and "loggedOut" siblingstates, each one having one "main" substate.

What I have to do now is to have it like this:

    ...
      name: 'loggedIn',
      initialSubstate: 'loggedIn.main',
      states: [{
        name: 'loggedIn.main'
      }]
    }, {
      name: 'loggedOut',
      initialSubstate: 'loggedOut.main',
      states: [{
        name: 'loggedOut.main'
      }]

Would it be a good feature to allow same name on substates (eg. stativus automatically append the prefix to make it a full path "loggedIn.main" when I add "main")?

Then I could do:

    ...
      name: 'loggedIn',
      initialSubstate: 'main',
      states: [{
        name: 'main'
      }]
    }, {
      name: 'loggedOut',
      initialSubstate: 'main',
      states: [{
        name: 'main'
      }]

Since if not, then having multiple nesting levels would create really long names, and if you change an ancestor state name you have to change them all etc.

Parallell substates aren't entered

I am using substatesAreConcurrent and have multiple substates. Still the substates aren't entered correctly:

http://jsfiddle.net/9XMFV/4/
http://jsfiddle.net/jVbMe/4/

The substates aren't entered. Seems to only work if you are entering one of the substates at the time.

Bug?

UPDATE:

I think this bug is the same as the above ones. Just to be sure I have made an example that hopefully will pass if the above one is fixed. This example is using one of the new features defining a state in an array (love this feature, the code is so much more DRY :))

http://jsfiddle.net/johnnywengluu/R8cVa/2/

State Modularizacion

We are trying to implement the following patter:

A modal wizard with multiple steps.

We are implementing as a State, that represents the wizard, and multiple substrates that represent the wizard steps.

This is a pattern that we use extensively: we expect to have many different wizards. Most steps are simple: once the wizard septs consider the work is valid, the next button can be enabled.

Other steps are more complex: as when some transaction needs to be done with a server.

Some steps might be useful in several wizards.

We got One Wizard perfectly working with Stativus, but the problem is now re-using it.

While Stativ allows reusing functions, Reusing substrates is not so easy. Apparently the main limitation is substate names cannot appear more than once globally.

It would be very nice to have one: ProfileWizard, state, and a SignUPWizard... even those having substates with same name: Step1...StepN

We understand the potential conflict: if a gotoState("Sept2") was issued, with several wizards instantiated. But that is not an actual use case: Having a different ParentState, i.e. the wizard name should be enough.

Is this something that can be implemented?

Is it possible to reuse States(with substrates) as a whole by just doing minor changes?

Thanks and regards!

Question: should events always trigger state transition?

After reading some texts it seems that an event should always trigger a state transition. Is this correct?

Eg. if I wanan display something when someone has pressed a button, instead of placing the code in the event handler, I place it in enterState() in the state transitioned to? Is this better than placing things in event handlers directly?

How do I know when to place logic in event handlers and when to place it in states (enterState)?

Could you say that if new actions (events) should be available after I pressed the button I should put it in a state. If not, then I have it in an event handler?

Gotcha: Namespace for global variables

There are two global variables used in Stativus: State and Statechart.

Could these names be namespaced (eg. Stativus.State and Stativus.Statechart)? This would reduce risk for errors when someone is including the library.

Spent quite of a time trying to figure out what the problem was. I had State inside a file :)

Transitioning to substate

I have two states - both parented by 'base'

http://cl.ly/0F0O1N2N3i2h1L1l3n3D

If I'm in production_list and sendEvent('viewCall', aCall) which is defined in 'base' state and looks like:

viewCall:function(aCall) {
    aController.set('content',aCall);
    this.goToState('call_detail');
}

I see the exit_state for the production_list and production states

I see only the enter state for 'calls' - e.g. it never transitions to the desired substate.

In goToState, I see it determine the correct common state = 'base' . I would expect cascadeEnterSubstates to transition through 'calls' and then enter call_detail

Any thoughts?

BUG?Both Substate and ParentState Handling the Same Event

statechart.addState("Sub3", {
  parentState:"Main",
  initialSubstate:"Sub31",
  Timeout:function() { 
    this.goToState("End");
  }
});
  statechart.addState("Sub31", {
    parentState:"Sub3",
    Tr31_32:function() { 
      this.goToState("Sub32");
    }
  });
  statechart.addState("Sub32", {
    parentState:"Sub3",
    Timeout:function() { 
      this.goToState("Sub31");
    }
  });

statechart.sendEvent('Timeout');

"Timeout" event is handled by both a parent state "Sub3" and its substate "Sub32". Who should handle the event when there are 2 choices?

Say we are in Sub32 and "Timeout" event is fired, my testing with the debug version shows that the statechart will enter Sub31 and then immediately exit Sub3 and enter End i.e. "Timeout" is fired in the Sub32 first and then in Sub3 immediately. So the same event is handled twice - one by the substate another the parent. Is this the right semantic? My understanding is that ONLY the substate should handle the Timeout event if it can handle it. Only when the current substate does not handle the given event should the parent state handle it.

The 'Timeout event for the parent State Sub3 should be the default action only when the substate cannot handle it. But if the substate can handle the event, there is no point to invoke Sub3's handler, too.

Wrong order in log

I have a Hide and Show state.

In the Hide state I have showSignIn event handler.

From a state I send a "showSignIn" event and I see these lines in the log:

EXIT: store.front.sign_in.Hide
ENTER: store.front.sign_in.Show
EVENT: store.front.sign_in.Hide fires [showSignIn] with 0 argument(s)

Shouldn't the EVENT row be the first log message. That would make the debugging easier: event -> state transition.

Internet Explorer 6.0+ support

I have submitted a pull request to add support for Internet Explorer 6.0+

#40

This will address stativus support for Internet Explorer 6.0+ (windows XP SP2 base install). The lag of forEach and indexOf support in <IE9 raises a permission denied error on production installations right now.

Question: Static vs Dynamic approach

I have some thoughts about how this statechart should operate.

Dynamic - serial

When it comes to one substate at a time I have some cases where I have a parent state with no initialSubstate (since you said that was ok).

In the parent state's enterState() I will check the URL hash what substate to enter (so that the user can send the link to another user and he/she will see the same page). It could be Search, Books, Users etc.

Dynamic - parallell

However, for concurrent substates I am forced to use substatesAreConcurrent. That means all substates are entered immediately after enterState() of the parent is run. The enterState() can no longer choose to enter the substates or not, or picking which ones to enter.

Isn't it better if I could choose which parallell substates to enter in the parent's enterState()? Eg. a webstore may have a Shopping cart and a Store view (Search, Books, Users etc).

Then in the parent's enterState() I could choose to either enter both Store and ShoppingCart, only Store but not ShoppingCart (maybe the user isn't buying stuff) or none of them.

Dynamic or static

Maybe my suggestion for a more dynamic approach is against how a statechart should work.

The static architecture right now forces me to have the concurrent states entered upfront. I could accomplish the same thing by having a Hidden and a Showing substate in each state. So when the ShoppingCart is entered it will immediately be Hidden til I switch to it's Showing substate.

Is this static approach a better one and follows the principles of a statechart?

Sum up

Before I chose to dynamically enter a substate I used to use initialSubstate: "loading" in the parent. It always entered a Loading state and in there I switched to the appropriate state. Now I don't have initialSubstate and is having the "routing logic" in the parent's enterState directly without having to go through a loading substate.

It seems that if this is okay then it should be a dynamical solution for substatesAreConcurrent too.

BUG: Concurrent event handler isn't triggered

I think I found a bug.

I have two concurrent states which registers an event handler with the same name.

However, when I fire the event, only one of them is triggered. I haven't returned "true" so the event should propagate.

I have recreated this weird behavior here: http://jsfiddle.net/johnnywengluu/ythns/1/

  • When you click the button it will fire the event.
  • I have commented the event handler that isn't triggered.
  • I have commented the event handler that is triggered.
  • I have commented what section to delete for it to work.

This is a good example of how useful nested states are. If the nested states bug is fixed first, I can recreate this code so that it will be simpler to get the statechart. Would want the nested architecture too in my real app or else it is too much anti-DRY and high typo risk.

Feature: Support for asynchronous coding

In today's environment a lot of things need to be asynchronous.

enterState() and exitState() doesn't support it at the moment.

Eg. I wanna make an ajax call in enterState() and enter the appropriate substate after I have the response and have set things up.

Suggestion: A simple way to achieve this would be to give me a callback in enterState(ready) that I call when it's completed.

Bug: Substates are unrecognized.

Found another minor bug:

This one works normally: http://jsfiddle.net/johnnywengluu/XKRqj/2/
This one doesn't since there is no hash in the array: http://jsfiddle.net/johnnywengluu/XKRqj/4/
This one works since there is a hash in the array: http://jsfiddle.net/johnnywengluu/XKRqj/5/

Another example but using initialSubstate: http://jsfiddle.net/johnnywengluu/XKRqj/6/

Reasons for fix:

  • The first example worked without a hash.
  • The last example gives "undefined" in the console.
  • Sometimes you want an empty state (eg. "HIDDEN" that is just a way to exit "SHOWN").

getData() for only that state

There are times I need to check if there is data stored for only the current state.

That is I don't care if the parent states hold the data with the same name.

Would it make sense to have something like

this.getData('view', false)

to only check for "view" in the current state and not propagate to the parent states if nothing is found?

Questions: How to navigate to a parent state from a child?

Right now if you're in a child state you can't navigate to any of the parent states in the tree via goToState. The call to _checkAllCurrentStates checks prevents goToState from continuing when it detects this condition.

What is the correct way to navigate back to a parent state from a child?

Example use case: Let's say of I have table of data that lists models fetched from the server, it does this within state "mydata.list". Above the list is an "Add New Record Button" when that's clicked I want to continuing displaying the list while also adding a form above the list to create a new entry. So I create a substate of "mydata.list" and I call it "mydata.list.new". Let's say the user clicks cancel on the form, I want to remove the form from the DOM and continue displaying the list. Ideally I would like to exit "mydata.list.new" and return to "mydata.list". But that navigation isn't supported.

Only alternative I found is to create a another state on the same level as "mydata.list" and call it "mydata.resetlist". I go to that state when the form is cancelled and then from there I can navigate back to "mydata.list" via goToState. Only downside is it causes the list state to exit and re-enter which I'd prefer to avoid.

Built-in Support of Timeout Event

I found that I often need to include a Timeout event in various substates (e.g. waiting for AJAX response). Currently, the way I achieve this is to update a single global startTime variable in all my substate's enterstate function and have some routine to generate the Timeout event by checking against this startTime variable. But this cause duplicate code in all my substates' enterstate function.

I think timeout is such a universal event that some sort of built-in support is appropriate. Perhaps, the simplest way is to expose an automatically updated global variable in statechart object that shows the time that the last change of state occurred.

Compatibility with AMD loaders like Require.js

I started using Stativus on a Backbone project that also uses require.js. I just wrapped everything in a define function but it would be great if there was native support for using AMD loaders.

Feature: debug version of Stativus

At the moment I am setting up a lot of custom console.log() lines.

It would ease out the development process if there was a debug version of Stativus that would output:

  • What state was entered/exited.
  • What event was fired: which states are listed as handlers and which one that actually took care of it.
  • Which ones are the active states.
    Etc.

That would save a lot of time for us who are living in a statechart :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.