Skip to content

Instantly share code, notes, and snippets.

@scottserok
Last active July 22, 2018 13:19
Show Gist options
  • Save scottserok/bce447843ec19411880fcfd068c695a7 to your computer and use it in GitHub Desktop.
Save scottserok/bce447843ec19411880fcfd068c695a7 to your computer and use it in GitHub Desktop.
Multi-step form with support for datepicker and chosen-select written in Coffeescript.
# Abstract Wizard to assist user with building a resource step by step.
# Include https://daneden.github.io/animate.css/ for animations.
#
# <div class="step"> are icons used to indicate which step the user is currently in
#
# <fieldset> are used to define what is displayed in each step of the form
#
# There should be equal number of .step elements as there are fieldset elements
# Create an instance of App.Wizard with the div ID of the modal
# 1 form per App.Wizard instance
#
# @param [String] modal_id The div that the multi-step form elements resides in.
#
# @example
# %a{ href: '#', data: { toggle: 'modal', target: '#myModal' } }
# Start
# #myModal.modal.fade{ role: 'dialog' }
# .modal-dialog
# .modal-content
# .modal-body
# .steps
# .step
# .step
# %form{ action: '/' }
# %fieldset
# %label
# Step 1
# %input
# .step-next
# Next
# %fieldset
# %label
# Step 2
# %input
# %a{ type: 'submit' }
# :javascript
# new App.Wizard('#myModal');
class App.Wizard
constructor: (@modal_id) ->
@current_step = 0
@high_water_mark = @current_step
@fieldsets = $ @modal_id + ' fieldset'
@steps = $ @modal_id + ' .step'
$ @fieldsets
.first()
.addClass 'active'
$ @steps
.first()
.addClass 'active'
$ @modal_id + ' .datepicker'
.datepicker
onSelect: (date_string) ->
$(@).siblings('input').val(date_string)
@setupStepNavigation()
# setup Next Step and Prev Step buttons and setup step icon click event
setupStepNavigation: ->
$ '.step-next'
.click =>
@nextSet()
$ '.step-prev'
.click =>
@prevSet()
for step, index in $ @modal_id + ' .step'
$ step
.data 'step-id', index # start numbering at 0
$ step
.click (e) =>
i = $(e.currentTarget).data 'step-id'
if i <= @high_water_mark
@goToSet i
else
@goToSet @high_water_mark
# click on a step icon will take to you that step without animation
goToSet: (n) ->
@current_step = n
$ @steps
.removeClass 'active'
$ @fieldsets
.removeClass 'active animated fadeOutLeft fadeOutRight fadeInLeft fadeInRight'
$ @steps[@current_step]
.addClass 'active'
$ @fieldsets[@current_step]
.addClass 'active'
# animate to next fieldset
nextSet: ->
if @currentStepIsValid()
if @current_step >= @fieldsets.size() - 1
@submitForm()
else
@current_step = @current_step + 1
$ @modal_id + ' fieldset.active'
.addClass 'animated'
.addClass 'fadeOutLeft'
setTimeout =>
$ @fieldsets[@current_step-1]
.removeClass 'active animated fadeOutLeft fadeOutRight fadeInLeft fadeInRight'
$ @fieldsets[@current_step]
.addClass 'active'
$ @fieldsets[@current_step]
.addClass 'animated'
.addClass 'fadeInRight'
, 500
@showSet @current_step
# animate to previous fieldset
prevSet: ->
if @current_step > 0
@current_step = @current_step - 1
$ @modal_id + ' fieldset.active'
.addClass 'animated'
.addClass 'fadeOutRight'
setTimeout =>
$ @fieldsets[@current_step+1]
.removeClass 'active animated fadeOutLeft fadeOutRight fadeInLeft fadeInRight'
$ @fieldsets[@current_step]
.addClass 'active'
$ @fieldsets[@current_step]
.addClass 'animated'
.addClass 'fadeInLeft'
, 500
@showSet @current_step
# comment routine when showing a fieldset
showSet: (n) ->
@current_step = n
if @current_step > @high_water_mark
@high_water_mark = @current_step
$ @modal_id + ' .step.active'
.removeClass 'active'
$ $(@modal_id + ' .step')[n-1]
.addClass 'finished'
$ $(@modal_id + ' .step')[n]
.addClass 'active'
$ @modal_id + ' form fieldset.active input'
.focus()
# minimal input validation and animation
currentStepIsValid: ->
if $(@modal_id + ' form fieldset.active select.required')[0]
if $(@modal_id + ' form fieldset.active select.required').val()?.length > 0
return true
else
$ @modal_id + ' form fieldset.active select.required'
.parent()
.addClass 'animated shake'
return false
if $(@modal_id + ' form fieldset.active input.required').val() == ''
$ @modal_id + ' form fieldset.active input.required, form fieldset.active .datepicker'
.addClass 'animated shake'
return false
true
submitForm: ->
$ @modal_id + ' form'
.submit()
.wizard { overflow:hidden; }
.wizard > .steps { text-align:center; margin-top:20px; }
/* Adjust the height, width, and padding if you won't be putting icons inside of the .step div */
.wizard > .steps > .step {
height: 25px;
width: 25px;
padding: 3px;
margin: 0 2px;
background-color: #bbbbbb;
border: none;
border-radius: 50%;
display: inline-block;
opacity: 0.5;
}
.wizard > .steps > .step.active { opacity:1; }
.wizard > .steps > .step.finished { background-color:#4CAF50; }
.wizard > fieldset { margin-top:20px; display:none; width:100%; }
.wizard > fieldset .ui-datepicker-inline { margin:auto; }
.wizard > fieldset.active { display:inline; }
.wizard > fieldset input.required { border:solid 1px red; }
.wizard > fieldset .chosen-drop { position: inherit; }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment