Created
November 26, 2012 21:45
-
-
Save mxriverlynn/4150820 to your computer and use it in GitHub Desktop.
A backbone / marionette state machine for wizard / workflow
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
MyApp.module('MyApp.SomeBuilder', function(SomeBuilder, App, Backbone, Marionette, $, _){ | |
'use strict'; | |
// Controller | |
// ---------- | |
SomeBuilder.Controller = Marionette.Controller.extend({ | |
initialize: function(options){ | |
this.navbarRegion = options.navbarRegion; | |
this.mainRegion = options.mainRegion; | |
var workflow = this._initWorkflow(); | |
this._setupNavigation(workflow, this.navbarRegion, this.footerRegion){ | |
}, | |
showPool: function(pool){ | |
// create view, show in a region | |
}, | |
selectShape: function(pool){ | |
// create view, show in a region | |
}, | |
selectCorners: function(pool){ | |
// create view, show in a region | |
}, | |
selectHopper: function(pool){ | |
// create view, show in a region | |
}, | |
selectDimensions: function(pool){ | |
// create view, show in a region | |
}, | |
selectSteps: function(pool){ | |
// create view, show in a region | |
}, | |
selectDetail: function(pool){ | |
// create view, show in a region | |
}, | |
_initWorkflow: function(pool){ | |
this.layout = new SomeLayout(); | |
App.someRegion.show(this.layout); | |
this.workflow = this._buildWorkflow(pool); | |
}, | |
_buildWorkflow: function(pool){ | |
var workflow = new App.MyWorkflow.Controller(); | |
workflow.addStep('', this.showPool, this); | |
workflow.addStep('shape', this.selectShape, this); | |
workflow.addStep('hopper', this.selectHopper, this); | |
workflow.addStep('corners', this.selectCorners, this); | |
workflow.addStep('dimensions', this.selectDimensions, this); | |
workflow.addStep('steps', this.selectSteps, this); | |
workflow.addStep('detail', this.selectDetail, this); | |
// always do this before moving to the next step | |
workflow.beforeMove(function(done){ | |
this._saveIt(done); | |
}, this); | |
return workflow; | |
}, | |
_saveIt: function(done){ | |
this.myModel.save(null, { | |
success: function(){ | |
done(); | |
} | |
}); | |
}, | |
_setupNavigation: function(pool, workflow, navbarRegion, footerRegion){ | |
var nav = new SomeBuilder.Navigation.Controller({ | |
workflow: workflow, | |
navbarRegion: navbarRegion, | |
footernavRegion: footerRegion | |
}); | |
return nav; | |
} | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
MyApp.module("MyWorkflow", function(Workflow, App, Backbone, Marionette, $, _){ | |
// Workflow Steps | |
// ---------------- | |
Workflow.WorkflowStep = Backbone.Model.extend({ | |
initialize: function(){ | |
var selectable = new Backbone.Picky.Selectable(this); | |
_.extend(this, selectable); | |
} | |
}); | |
Workflow.WorkflowStepCollection = Backbone.Collection.extend({ | |
model: Workflow.WorkflowStep, | |
initialize: function(){ | |
this.emptyStep = new this.model({isEmpty: true}); | |
var selectable = new Backbone.Picky.SingleSelect(this); | |
_.extend(this, selectable); | |
}, | |
getNext: function(){ | |
var index, nextIndex; | |
if (!this.selected){ | |
index = 0; | |
} else { | |
index = this.indexOf(this.selected); | |
} | |
if (index < this.length){ | |
nextIndex = index + 1; | |
} else { | |
nextIndex = -1; | |
} | |
return this.at(nextIndex) || this.emptyStep; | |
}, | |
getPrevious: function(){ | |
var index, nextIndex; | |
if (!this.selected){ | |
index = 0; | |
} else { | |
index = this.indexOf(this.selected); | |
} | |
if (index > 0){ | |
nextIndex = index - 1; | |
} else { | |
nextIndex = -1; | |
} | |
return this.at(nextIndex) || this.emptyStep; | |
} | |
}); | |
// Raw step data | |
// ------------- | |
var workflowStepData = [ | |
{ | |
id: 1, | |
key: "", | |
name: "Info" | |
}, | |
{ | |
id: 2, | |
key: "shape", | |
name: "Shape" | |
}, | |
{ | |
id: 3, | |
key: "corners", | |
name: "Corners" | |
}, | |
{ | |
id: 4, | |
key: "hopper", | |
name: "Hopper" | |
}, | |
{ | |
id: 5, | |
key: "dimensions", | |
name: "Dimensions" | |
}, | |
{ | |
id: 6, | |
key: "steps", | |
name: "Steps" | |
}, | |
{ | |
id: 7, | |
key: "detail", | |
name: "Detail" | |
} | |
]; | |
// Workflow Controller | |
// ------------------- | |
Workflow.Controller = Marionette.Controller.extend({ | |
initialize: function(options){ | |
this.steps = new Workflow.WorkflowStepCollection(workflowStepData); | |
this.filters = {}; | |
}, | |
getSteps: function(){ | |
return this.steps; | |
}, | |
nextStep: function(){ | |
var nextStep = this.steps.getNext(); | |
this.moveTo(nextStep); | |
}, | |
previousStep: function(){ | |
var previousStep = this.steps.getPrevious(); | |
this.moveTo(previousStep); | |
}, | |
moveTo: function(step){ | |
this._triggerStep(step); | |
}, | |
addStep: function(stepKey, handler, context){ | |
this.bindTo(this, "step:" + stepKey, handler, context); | |
}, | |
beforeMove: function(fn, context){ | |
this.filters.beforeMove = {fn: fn, context: context}; | |
}, | |
setStepByKey: function(stepKey){ | |
stepKey = stepKey || ""; | |
var step = this.steps.where({key: stepKey})[0]; | |
if (step){ | |
step.select(); | |
} | |
}, | |
_triggerStep: function(step){ | |
var key = step.get("key"); | |
var done = _.bind(function(){ | |
step.select(); | |
this.trigger("step:" + key); | |
}, this); | |
var beforeMove = this.filters.beforeMove; | |
if (_.isObject(beforeMove)){ | |
beforeMove.fn.call(beforeMove.context, done); | |
} else { | |
done(); | |
} | |
} | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi Derick, first off all, thanks for the gist, it's very helpful :)
I think you have a mistake in "app_steps.js" on line 12: the call is missing the pool argument, or I'm not getting this at all :
I wanted to know if you have any implemented code with this pattern that I can take a look on to get a better grasp on how it's used.
Thanks,
scancel.