Skip to content

Instantly share code, notes, and snippets.

@nikhgupta
Last active January 4, 2016 03:19
Show Gist options
  • Save nikhgupta/8560998 to your computer and use it in GitHub Desktop.
Save nikhgupta/8560998 to your computer and use it in GitHub Desktop.
FuelUX Form Wizard in AngularJS
<wizard class="form-horizontal" id="timeline">
<step title="Welcome">
<label for="title">Title (required):</label>
<input type="text" name="title" id="title" class="form-control"
required placeholder="Your Timeline Title" ng-model="currEL.title" />
<ul ng-show="$$prevSibling.step.title.$dirty && $$prevSibling.step.title.$invalid" class="ng-error-list">
<li ng-show="$$prevSibling.step.title.$error.required">An eventline, definitely, needs a title. Don't you think?</li>
</ul>
<!-- TODO: maybe use errors like this for every step -->
<!-- <errors> -->
<!-- <error for="title" on="required">An eventline, definitely, needs a title. Don't you think?</error> -->
<!-- </errors> -->
</step>
<step title="Add Events">
<!-- .. -->
</step>
<step title="Finish">
<!-- .. -->
</step>
</wizard>
<div class="step-pane" ng-class="{active: active}" ng-transclude id='{{title | lowercase}}' ng-form="step">
<!-- TODO: filter should convert title to snake case -->
</div>
<form novalidate class='{{class}}' id='{{id}}' name='{{id}}'>
<div class="wizard clearfix">
<ul class="steps">
<li ng-repeat='step in steps()' ng-class='{active: step.active}' data-target='#{{step.title | lowercase}}'><span class="badge" ng-class="{'badge-info': step.active}">{{step.id}}</span>{{step.title}}</li>
</ul>
</div>
<div class="step-content">
<div ng-transclude></div>
<div class="actions m-t">
<button type="button" ng-disabled="current().id < 2" class="btn btn-default btn-sm btn-prev" ng-click="prev()">Prev</button>
<button type="button" ng-disabled="stepIsInvalid()" class="btn btn-default btn-sm btn-next" ng-click="next()" data-next="Next" data-last="Finish">Next</button>
</div>
</div>
</form>
@app.directive "wizard", ->
restrict: "EA"
replace : true,
require: "wizard"
transclude: true
controller: "WizardCtrl"
templateUrl: "wizard.html"
scope: {
id: "@"
class: "@"
}
link: (scope, element, attrs, wizardCtrl) ->
wizardCtrl.addWizard scope, element
@app.directive "step", ->
require: "^wizard"
restrict: "EA"
transclude: true
replace: true
templateUrl: "step.html"
scope: {
active: "=?"
title: "@"
}
link: (scope, element, attrs, wizardCtrl) ->
wizardCtrl.addStep scope, element
# when the scope is destroyed then remove the step from current steps array
scope.$on '$destroy', ->
wizardCtrl.removeStep scope
# keep a watch on when this step becomes active
# scope.$watch 'active', (active) ->
# wizardCtrl.select(scope) if active
@app.controller 'WizardCtrl', ($scope) ->
# some needed variables
steps = @steps = []
@currentStep = null
destroyed = false
@element = null
# some utility functions
@stepId = (step) -> steps.indexOf(step)
@totalSteps = -> steps.length
@hasSteps = -> @totalSteps > 0
@lastStep = -> steps[@totalSteps - 1]
# add the wizard a.k.a. store somethings..
@addWizard = (wizard, element) ->
$scope.$element = element
# find out the next and previous buttons
@nextBtn = element.find(".actions .btn-next")
@prevBtn = element.find(".actions .btn-prev")
@nextBtn.on 'click', @moveForward
@prevBtn.on 'click', @moveBackward
# add a step to the wizard
@addStep = (step, element) ->
step.id = steps.length + 1
step.$element = element
steps.push step
stepContent = element.closest(".step-content")
@activateStep step if steps.length is 1 or step.active
# remove a step from the wizard
@removeStep = (step) ->
index = @stepId(step)
steps.splice index, 1
# activate the previous step when this step was removed
previousIndex = if index >= @totalSteps then index - 1 else index
@activateStep steps[previousIndex]
# select a step and make it active
@activateStep = (step) ->
step.active = true
@currentStep = step
@stepIsValid = ->
@currentStep.step.$dirty && @currentStep.step.$valid
@moveForward = ->
console.log 'moving forward'
@moveBackward = ->
console.log 'moving backward'
@moveTo = (step) ->
console.log 'moving to given step'
# set a flag to know when this directive is being destroyed..
$scope.$on '$destroy', -> destroyed = true
# expose certain methods..
$scope.steps = -> steps
$scope.current = => @currentStep
$scope.isActive = (step) => @currentStep == step
$scope.select = (step) => @activateStep step
$scope.stepIsInvalid = => not @stepIsValid()
return
Copy link

ghost commented Jan 22, 2015

Thanks for the example, but agreed with the previous - you should post Javascript instead of CoffeeScript in the future. Bit unnecessary to post a precompiler language.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment