New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
BUG: concurrent state's child state is never entered #38
Comments
Not really a bug: var statechart; //////////////////////////////////////////// statechart.addState('application', { statechart.addState('page', { statechart.initStates({'default': 'application'}); /** [~/Desktop]$ node statey.js rvm:ruby-1.9.3-p125 |
Yes, this works when you're using 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
// - login
// - page (#nav and #content are concurrent)
// - page#nav
// - page#nav#first <-- BUG, NEVER LOADS
// - page#content
////////////////////////////////////////////
statechart.addState('application', {
initialSubstate: 'login'
});
statechart.addState('login', {
parentState: 'application'
, enterState: function(){ console.log('login loaded'); } //<-- fires
, login_success: function(){ this.goToState("page#nav#first"); }
})
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('application');
statechart.sendEvent('login_success');
console.log(statechart.currentState().map(function(state){ return state.name; }));
// the above line should print something like:
// ['page#nav#second', 'page#nav', 'page#content', 'page', 'application']
// instead, it prints:
// ['page#nav', 'page#content', 'page', 'application']
// WHERE IS 'page#nav#first' ??? |
As per @sevifives comments... |
did you run the second repro scenario that uses |
var statechart; //////////////////////////////////////////// statechart.addState('application', { statechart.addState('login', { statechart.addState('page', { statechart.initStates({'default':'application'}); // this works ENTER: application |
yes, see how "ENTER: page#nav#first" is never logged and the array at the end is missing "page#nav#first"? |
@troygoode it is entered (look at the 5th ENTER: from the top)...I don't understand why it isn't in the array at the end.. |
I've never tried to jump to the substate of another state. That seems a little odd to me. 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
// - login
// - page (#nav and #content are concurrent)
// - page#nav
// - page#nav#first <-- BUG, NEVER LOADS
// - page#content
////////////////////////////////////////////
statechart.addState('application', {
initialSubstate: 'login'
});
statechart.addState('login', {
parentState: 'application'
, enterState: function(){ console.log('login loaded'); } //<-- fires
, login_success: function(){ this.goToState("page"); }
})
statechart.addState('page', {
parentState: 'application'
, initialSubstate: 'page#nav'
, substatesAreConcurrent: true
, states: [
{
name: 'page#nav'
, initialSubstate: 'page#nav#first'
, 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({'default':'application'});
statechart.sendEvent('login_success');
console.log(statechart.currentState().map(function(state){ return state.name; })); ENTER: application |
@sevifives, 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
// - login
// - page (#nav and #content are concurrent)
// - page#nav
// - page#nav#first <-- BUG, NEVER LOADS
// - page#content
////////////////////////////////////////////
statechart.addState('application', {
initialSubstate: 'login'
});
statechart.addState('login', {
parentState: 'application'
, enterState: function(){ console.log('login loaded'); } //<-- fires
, login_success: function(){ this.goToState("page#nav#second"); } // <-- doesn't work
//, login_success: function(){ this.goToState("page"); } // <-- fires page#nav#first
})
statechart.addState('page', {
parentState: 'application'
, substatesAreConcurrent: true
, initialSubstate: 'page#nav'
, states: [
{
name: 'page#nav'
, enterState: function(){ console.log('nav loaded'); } //<-- fires
, initialSubstate: 'page#nav#first'
, states:[
{
name: 'page#nav#first'
, enterState: function(){ console.log('nav.1 loaded'); } //<-- fires
},
{
name: 'page#nav#second'
, enterState: function(){ console.log('nav.2 loaded'); } //<-- NEVER fires
}
]
},
{
name: 'page#content'
, enterState: function(){ console.log('content loaded'); } //<-- fires
}
]
});
statechart.initStates({'default': 'application'});
statechart.sendEvent('login_success');
console.log(statechart.currentState().map(function(state){ return state.name; }));
// the above line should print something like:
// ['page#nav#second', 'page#nav', 'page#content', 'page', 'application']
// instead, it prints:
// ['page#nav', 'page#content', 'page', 'application']
// WHERE IS 'page#nav#second' ??? ENTER: application |
This is how I see it: var statechart;
if(require) // I'm using node to make this easier to test
statechart = require('./stativus').createStatechart();
else
statechart = Stativus.createStatechart();
statechart.addState('application', {
initialSubstate: 'login',
substatesAreConcurrent: true
});
statechart.addState('login', {
parentState: 'application'
, enterState: function(){ console.log('login loaded'); }
, verify_this: function () {
statechart.sendEvent('login_success');
}
})
statechart.addState('page', {
parentState: 'application'
, initialSubstate: 'noPage'
, states: [
{
name: 'noPage'
, login_success: function () {
this.goToState('page#nav');
}
},
{
name: 'page#nav'
, initialSubstate: 'page#nav#first'
, enterState: function(){ console.log('nav loaded'); }
, states:[
{
name: 'page#nav#first'
, enterState: function(){ console.log('nav.1 loaded'); }
}
]
},
{
name: 'page#content'
, enterState: function(){ console.log('content loaded'); }
}
]
});
statechart.initStates({'default':'application'});
statechart.sendEvent('verify_this');
console.log(statechart.currentState().map(function(state){ return state.name; })); ENTER: application |
Not an acceptable solution. What do you do when Edit: also, that code is very spaghetti |
something doesn't look right...i'll look into it. |
This code is closer to my real-life need: |
I just discovered this (likely) doesn't have anything to do with concurrent states, but is actually a problem with attempting to goToState where your target is a child of a sibling state (nephew/niece state?): var Stativus = require('./stativus');
var statechart = Stativus.createStatechart();
statechart.addState('application', {
initialSubstate: 'page1'
});
statechart.addState('page1', {
parentState: 'application'
, go: function(){ this.goToState('page2.2'); }
});
statechart.addState('page2', {
parentState: 'application'
, initialSubstate: 'page2.1'
});
statechart.addState('page2.1', {
parentState: 'page2'
});
statechart.addState('page2.2', {
parentState: 'page2'
});
statechart.initStates('application');
statechart.sendEvent('go');
console.log(statechart.currentState().map(function(state){ return state.name; }));
// expect to see [ 'page2.2', 'page2', 'application'], instead I get:
/*
troy:~/dev/foo $ node test.js
ENTER: application
ENTER: page1
EVENT: page1 fires [go] with 0 argument(s)
EXIT: page1
ENTER: page2
[ 'page2', 'application' ]
*/ |
@troygoode great catch...this only happens when you have a single parent with child states as the first state. Technically your code should look like this: var Stativus = require('./stativus');
var statechart = Stativus.createStatechart();
statechart.addState('page1', {
, go: function(){ this.goToState('page2.2'); }
});
statechart.addState('page2', {
, initialSubstate: 'page2.1'
});
statechart.addState('page2.1', {
parentState: 'page2'
});
statechart.addState('page2.2', {
parentState: 'page2'
});
statechart.initStates('page1');
statechart.sendEvent('go');
console.log(statechart.currentState().map(function(state){ return state.name; }));
/*
troy:~/dev/foo $ node test.js
ENTER: page1
EVENT: page1 fires [go] with 0 argument(s)
EXIT: page1
ENTER: page2
ENTER: page2.2
[ 'page2.2','page2', 'application' ]
*/ |
i fixed the code so you can do the code that you wrote which should be permissible. |
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?
The text was updated successfully, but these errors were encountered: