Skip to content
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

Emit every state that is being transitioned to, instead of the leaf #113

Merged
merged 1 commit into from
Sep 15, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ module.exports = function StateProvider(makeRenderer, rootElement, stateRouterOp
var lastCompletelyLoadedState = CurrentState()
var lastStateStartedActivating = CurrentState()
var stateProviderEmitter = new EventEmitter()
var compareStartAndEndStates = StateComparison(prototypalStateHolder)

function stateNameToArrayofStates(stateName) {
return parse(stateName).map(function(name) {
return prototypalStateHolder.get(name)
})
}

StateTransitionManager(stateProviderEmitter)
stateRouterOptions = extend({
throwOnError: true,
Expand Down Expand Up @@ -239,10 +247,10 @@ module.exports = function StateProvider(makeRenderer, rootElement, stateRouterOp
}
return state
}).then(ifNotCancelled(function(state) {
stateProviderEmitter.emit('stateChangeStart', state, parameters)
stateProviderEmitter.emit('stateChangeStart', state, parameters, stateNameToArrayofStates(state.name))
lastStateStartedActivating.set(state.name, parameters)
})).then(function getStateChanges() {
var stateComparisonResults = StateComparison(prototypalStateHolder)(lastCompletelyLoadedState.get().name, lastCompletelyLoadedState.get().parameters, newStateName, parameters)
var stateComparisonResults = compareStartAndEndStates(lastCompletelyLoadedState.get().name, lastCompletelyLoadedState.get().parameters, newStateName, parameters)
return stateChangeLogic(stateComparisonResults) // { destroy, change, create }
}).then(ifNotCancelled(function resolveDestroyAndActivateStates(stateChanges) {
return resolveStates(getStatesToResolve(stateChanges), extend(parameters)).catch(function onResolveError(e) {
Expand Down Expand Up @@ -288,7 +296,7 @@ module.exports = function StateProvider(makeRenderer, rootElement, stateRouterOp
})).then(function stateChangeComplete() {
lastCompletelyLoadedState.set(newStateName, parameters)
try {
stateProviderEmitter.emit('stateChangeEnd', prototypalStateHolder.get(newStateName), parameters)
stateProviderEmitter.emit('stateChangeEnd', prototypalStateHolder.get(newStateName), parameters, stateNameToArrayofStates(newStateName))
} catch (e) {
handleError('stateError', e)
}
Expand Down
4 changes: 2 additions & 2 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,9 +246,9 @@ These are all emitted on the state router object.
### State change

- `stateChangeAttempt(functionThatBeginsTheStateChange)` - used by the state transition manager, probably not useful to anyone else at the moment
- `stateChangeStart(state, parameters)` - emitted after the state name and parameters have been validated
- `stateChangeStart(state, parameters, states)` - emitted after the state name and parameters have been validated
- `stateChangeCancelled(err)` - emitted if a redirect is issued in a resolve function
- `stateChangeEnd(state, parameters)` - after all activate functions are called
- `stateChangeEnd(state, parameters, states)` - after all activate functions are called
- `stateChangeError(err)` - emitted if an error occurs while trying to navigate to a new state - including if you try to navigate to a state that doesn't exist
- `stateError(err)` - emitted if an error occurs in an activation function, or somewhere else that doesn't directly interfere with changing states. Should probably be combined with `stateChangeError` at some point since they're not that different?
- `routeNotFound(route, parameters)` - emitted if the user or some errant code changes the location hash to a route that does not have any states associated with it. If you have a generic "not found" page you want to redirect people to, you can do so like this:
Expand Down
41 changes: 26 additions & 15 deletions test/emitters.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
var test = require('tape-catch')
var assertingRendererFactory = require('./helpers/asserting-renderer-factory')
var getTestState = require('./helpers/test-state-factory')
var mockRendererFacotry = require('./helpers/renderer-mock')

test('Emitting errors when attempting to navigate to invalid states', function(t) {
function testGoingTo(description, invalidStateName) {
Expand Down Expand Up @@ -55,7 +54,7 @@ test('Emitting stateChangeStart and stateChangeEnd', function(t) {
var renderer = assertingRendererFactory(t, [ parent1Template, child1Template, parent2Template, child2Template ])
var state = getTestState(t, renderer)
var stateRouter = state.stateRouter
var assertsBelow = 24
var assertsBelow = 28
var renderAsserts = renderer.expectedAssertions

t.plan(assertsBelow + renderAsserts)
Expand All @@ -65,76 +64,88 @@ test('Emitting stateChangeStart and stateChangeEnd', function(t) {
var secondParentActivate = false
var secondChildActivate = false

stateRouter.addState({
var valid1 = {
name: 'valid1',
route: '/valid1',
template: parent1Template,
activate: function(context) {
firstParentActivate = true
}
})

stateRouter.addState({
}
var valid1valid = {
name: 'valid1.valid',
route: '/valid1',
template: child1Template,
activate: function(context) {
firstChildActivate = true
}
})
}

stateRouter.addState({
var valid2 = {
name: 'valid2',
route: '/valid2',
template: parent2Template,
activate: function(context) {
secondParentActivate = true
}
})
}

stateRouter.addState({
var valid2valid = {
name: 'valid2.valid',
route: '/valid2',
template: child2Template,
activate: function(context) {
secondChildActivate = true
}
})
}

stateRouter.addState(valid1)
stateRouter.addState(valid1valid)
stateRouter.addState(valid2)
stateRouter.addState(valid2valid)

stateRouter.once('stateChangeStart', function(state, properties) {
stateRouter.once('stateChangeStart', function(state, properties, states) {
t.equal(state.name, 'valid1.valid')
t.deepEqual(properties, firstProperties)
t.notOk(firstParentActivate)
t.notOk(firstChildActivate)
t.notOk(secondParentActivate)
t.notOk(secondChildActivate)

t.deepEqual(states, [valid1, valid1valid])
})

stateRouter.once('stateChangeEnd', function(state, properties) {
stateRouter.once('stateChangeEnd', function(state, properties, states) {
t.equal(state.name, 'valid1.valid')
t.deepEqual(properties, firstProperties)
t.ok(firstParentActivate)
t.ok(firstChildActivate)
t.notOk(secondParentActivate)
t.notOk(secondChildActivate)

stateRouter.once('stateChangeStart', function(state, properties) {
t.deepEqual(states, [valid1, valid1valid])

stateRouter.once('stateChangeStart', function(state, properties, states) {
t.equal(state.name, 'valid2.valid')
t.deepEqual(properties, secondProperties)
t.ok(firstParentActivate)
t.ok(firstChildActivate)
t.notOk(secondParentActivate)
t.notOk(secondChildActivate)

t.deepEqual(states, [valid2, valid2valid])
})

stateRouter.once('stateChangeEnd', function(state, properties) {
stateRouter.once('stateChangeEnd', function(state, properties, states) {
t.equal(state.name, 'valid2.valid')
t.deepEqual(properties, secondProperties)
t.ok(firstParentActivate)
t.ok(firstChildActivate)
t.ok(secondParentActivate)
t.ok(secondChildActivate)

t.deepEqual(states, [valid2, valid2valid])

t.end()
})

Expand Down