Commit 63a4ab59 authored by Randall Leeds's avatar Randall Leeds

Simplify form error input handling

The form-input class now has the directive responsible for setting
the error classes. It watches its scope and sets the errors only
if the model is defined or pristine. This guard keeps the error class
from being set until validation passes (when the model becomes defined)
and keeps it from being cleared until the pristine state is reset.

The form-validate directive is now just a controller for form-input to
register with. It sets all fields to dirty and forces a render on
submit.

These mechanisms are better all around than trying to listen for a the
model to be undefined and setting pristine automatically. The model is
undefined whenever validation is failing. There are times when the from
should maybe be cleared but still show errors. Now, it is left up to
other code to set pristine if the form should be reset.
parent 5b433736
......@@ -79,15 +79,13 @@ authDirective = ['$timeout', ($timeout) ->
scope.onError()
scope.$on 'success', (event) ->
form.$setPristine()
scope.onSuccess()
scope.$on 'timeout', (event) ->
form.$setPristine()
scope.onTimeout()
scope.$watch 'model', (value) ->
if value is null
form.$setPristine()
scope.$watch 'tab', (name) ->
$timeout ->
elem
......
formValidate = ['$timeout', ($timeout) ->
link: (scope, elem, attr, form) ->
isSubmitted = false
formInput = ->
link: (scope, elem, attr, [form, model, validator]) ->
return unless form?.$name and model?.$name and validator
fieldClassName = 'form-field'
errorClassName = 'form-field-error'
toggleClass = (field, {addClass}) ->
inputEl = elem.find("[name=#{field.$name}]")
fieldEl = inputEl.parents(".#{fieldClassName}").first()
fieldEl.toggleClass(errorClassName, addClass)
render = model.$render
updateField = (field) ->
return unless field?
resetResponse = (value) ->
model.$setValidity('response', true)
value
if field.$valid or field.$pristine
toggleClass(field, addClass: false)
else if field.$dirty
toggleClass(field, addClass: true)
toggleClass = (addClass) ->
elem.toggleClass(errorClassName, addClass)
elem.parent().toggleClass(errorClassName, addClass)
# A custom parser for each form field that is used to reset the "response"
# error state whenever the $viewValue changes.
fieldParser = (field, value) ->
field.$setValidity('response', true)
updateField(field) if field.$valid
return value
model.$parsers.unshift(resetResponse)
model.$render = ->
toggleClass(model.$invalid and model.$dirty)
render()
forEachField = (fn) ->
fn(field) for own _, field of form when field?.$name?
validator.addControl(model)
scope.$on '$destroy', -> validator.removeControl this
forEachField (field) ->
parser = angular.bind(null, fieldParser, field)
field.$parsers.push(parser)
scope.$watch ->
if model.$modelValue? or model.$pristine
model.$render()
return
# Validate field when the content changes.
elem.on 'change', ':input', ->
forEachField(updateField)
require: ['^?form', '?ngModel', '^?formValidate']
restrict: 'C'
# Validate form on submit and set flag for error watcher.
elem.on 'submit', ->
isSubmitted = true
forEachField (field) ->
field.$setViewValue(field.$viewValue)
updateField(field)
scope.$watch form.$name + '.$error', ->
if isSubmitted
forEachField(updateField)
isSubmitted = false
, true
formValidate = ->
controller: ->
controls = {}
scope.$watch form.$name + '.$pristine', (value) ->
forEachField(updateField) if value is true
addControl: (control) ->
if control.$name
controls[control.$name] = control
require: 'form'
]
removeControl: (control) ->
if control.$name
delete controls[control.$name]
submit: ->
# make all the controls dirty and re-render them
for _, control of controls
control.$setViewValue(control.$viewValue)
control.$render()
link: (scope, elem, attr, ctrl) ->
elem.on 'submit', ->
ctrl.submit()
markdown = ['$filter', '$timeout', ($filter, $timeout) ->
......@@ -378,6 +378,7 @@ match = ->
angular.module('h.directives', ['ngSanitize', 'ngTagsInput'])
.directive('formInput', formInput)
.directive('formValidate', formValidate)
.directive('fuzzytime', fuzzytime)
.directive('markdown', markdown)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment