Skip to content

Instantly share code, notes, and snippets.

@milankinen
Last active December 16, 2015 22:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save milankinen/5505390 to your computer and use it in GitHub Desktop.
Save milankinen/5505390 to your computer and use it in GitHub Desktop.
# PART 2: bind our backbone view to validation events and also for
# input changes so that model changes automatically when input changes
# =======================================================================
# This defines which element's attribute will be used for linking
inputSelector = 'name'
# model update function, which is called when input changes
updateModel = (model, attr, value) ->
model.set(attr, value || null)
# This is called when input element is marked as valid
# It basically just removes Bootstrap error classes and
# custom error messages from input's control-group
setValid = ($input, attr, selector) ->
$group = $input.closest('.control-group')
return if $group.length == 0
$group.find('.help-inline.error').remove()
$group.removeClass('error')
return
# Helper function to check if input has already same an error message
containsError = ($err, $group) ->
errText = $err.text()
for help in $group.find('.help-inline.error')
return true if $(help).text() == errText
return false
# This is called when input is marked as valid
setInvalid = ($input, attr, errMsg, selector) ->
$group = $input.closest('.control-group')
if $group.length == 0
console.log "Invalid input '#{attr}' has no control group. No message will be shown..", $input
return
$controls = $group.find('.controls')
$err = $("<span class='help-inline error'>#{_.escape(errMsg)}</span>")
if !containsError($err, $group)
if $controls.length > 0
$err.insertAfter($controls).addClass('next-line')
else
$group.append($err)
# finally add error class
$group.addClass('error')
# This function is called when new stuff is rendered to the document
# It searches all inputs and binds update and validation events to
# those inputs so that changes/validation results are reflected automatically
# between model <-> view <-> template
addInputBindings = (view, model) ->
return if not model
view.$(':input:not(.btn)').each ->
$this = $(this)
return if not $this.attr(inputSelector)
# if we have backbone relational / nested plugin then we may have want
# to validate and update also nested attributes
attr = $this.attr(inputSelector).replace(/\-/g, '.')
# input change to model bindings
if !$this.data('ignore-model')
# when input changes, then models changes too
# we could add also events from model changes to change
# input value but we won't do it in this example
$this.on 'change', -> updateModel(model, attr, $this.val())
# validation bindings
if !$this.data('ignore-validation')
# remove previous
model.off "valid:#{attr}", null, view
model.off "invalid:#{attr}", null, view
# add new
model.on "valid:#{attr}", ((attr, selector) -> setValid($this, attr, selector)), view
model.on "invalid:#{attr}", ((attr, errMsg, selector) -> setInvalid($this, attr, errMsg, selector)), view
# This is base class for all our items
class window.ItemView extends Backbone.Marionette.ItemView
constructor: (options) ->
super
@on 'render', => addInputBindings(@, @model)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment