Commit bce25d56 authored by Randall Leeds's avatar Randall Leeds Committed by Aron Carroll

Form validation on blur improvements

Add a temprorary hack as a directive triggered by the form-error-list
class which polyfills the `ngModelController` methods `$setTouched` and
`$setUntouched`.

The form styles and the directive both rely on the form-error-list
element being nested as a sibling of the field to which it relates.
parent baa946e8
...@@ -714,8 +714,10 @@ class Auth ...@@ -714,8 +714,10 @@ class Auth
_reset = -> _reset = ->
delete $scope.errors delete $scope.errors
angular.extend $scope.model, base angular.extend $scope.model, base
for own _, ctrl of $scope when typeof ctrl?.$setPristine is 'function' for own _, ctrl of $scope when angular.isFunction ctrl?.$setPristine
ctrl.$setPristine() ctrl.$setPristine()
for own _, field of ctrl when angular.isFunction field?.$setUntouched
field.$setUntouched()
_error = (form, data) -> _error = (form, data) ->
{errors, reason} = data {errors, reason} = data
......
formErrorList = ->
link: (scope, elem, attr, form) ->
field = form[attr.target]
return unless field?
field.$setUntouched = ->
field.$untouched = true
field.$touched = false
elem.parent().children('input').removeClass('ng-touched')
field.$setTouched = ->
field.$untouched = false
field.$touched = true
elem.parent().children('input').addClass('ng-touched')
require: '^form'
restrict: 'C'
formValidate = ->
link: (scope, elem, attr, form) ->
elem.on 'blur', ':input', ->
form[this.name]?.$setTouched()
elem.on 'submit', (event) ->
for fieldName of form
form[fieldName]?.$setTouched?()
require: 'form'
markdown = ['$filter', '$timeout', ($filter, $timeout) -> markdown = ['$filter', '$timeout', ($filter, $timeout) ->
link: (scope, elem, attr, ctrl) -> link: (scope, elem, attr, ctrl) ->
return unless ctrl? return unless ctrl?
...@@ -104,32 +133,6 @@ recursive = ['$compile', '$timeout', ($compile, $timeout) -> ...@@ -104,32 +133,6 @@ recursive = ['$compile', '$timeout', ($compile, $timeout) ->
] ]
###
# The slow validation directive ties an to a model controller and hides
# it while the model is being edited. This behavior improves the user
# experience of filling out forms by delaying validation messages until
# after the user has made a mistake.
###
slowValidate = ->
link: (scope, elem, attr, ctrl) ->
fieldName = attr.slowValidate
return unless ctrl.$name? and ctrl?[fieldName]
elem.addClass 'slow-validate'
fieldPath = [ctrl.$name, fieldName, '$viewValue'].join('.')
modelCtrl = ctrl?[fieldName]
scope.$watch fieldPath, ->
if modelCtrl.$invalid and modelCtrl.$dirty
elem.addClass 'slow-validate-show'
else
elem.removeClass 'slow-validate-show'
require: '^form'
restrict: 'A'
tabReveal = ['$parse', ($parse) -> tabReveal = ['$parse', ($parse) ->
compile: (tElement, tAttrs, transclude) -> compile: (tElement, tAttrs, transclude) ->
panes = [] panes = []
...@@ -439,38 +442,14 @@ whenscrolled = ['$window', ($window) -> ...@@ -439,38 +442,14 @@ whenscrolled = ['$window', ($window) ->
scope.$apply attr.whenscrolled scope.$apply attr.whenscrolled
] ]
validateForm = ['$parse', ($parse) ->
require: 'form',
link: (scope, elem, attr, formController) ->
onSuccess = $parse(attr.validateForm)
touchedInputs = {} # Inputs that the user has blurred.
scope.isFieldValid = (fieldName) ->
field = formController[fieldName]
unless field
throw new Error("The #{field} field could not be found on this form")
touchedInputs[fieldName] && field.$dirty && field.$invalid
scope.fieldClass = (fieldName, defaults, error) ->
if scope.isFieldValid(fieldName) then "#{defaults} #{error}" else defaults
elem.on 'submit', (event) ->
Object.keys(formController).forEach (prop) ->
if prop.indexOf('$') != 0
formController[prop].$dirty = true
touchedInputs[prop] = true
elem.on 'blur', ':input', ->
touchedInputs[this.name] = true
scope.$apply()
]
angular.module('h.directives', ['ngSanitize']) angular.module('h.directives', ['ngSanitize'])
.directive('formErrorList', formErrorList)
.directive('formValidate', formValidate)
.directive('fuzzytime', fuzzytime) .directive('fuzzytime', fuzzytime)
.directive('markdown', markdown) .directive('markdown', markdown)
.directive('privacy', privacy) .directive('privacy', privacy)
.directive('recursive', recursive) .directive('recursive', recursive)
.directive('slowValidate', slowValidate)
.directive('tabReveal', tabReveal) .directive('tabReveal', tabReveal)
.directive('tags', tags) .directive('tags', tags)
.directive('thread', thread) .directive('thread', thread)
...@@ -479,4 +458,3 @@ angular.module('h.directives', ['ngSanitize']) ...@@ -479,4 +458,3 @@ angular.module('h.directives', ['ngSanitize'])
.directive('repeatAnim', repeatAnim) .directive('repeatAnim', repeatAnim)
.directive('visualSearch', visualSearch) .directive('visualSearch', visualSearch)
.directive('whenscrolled', whenscrolled) .directive('whenscrolled', whenscrolled)
.directive('validateForm', validateForm)
...@@ -173,18 +173,6 @@ h6 { ...@@ -173,18 +173,6 @@ h6 {
display: none; display: none;
} }
.slow-validate {
display: block;
font-family: $sansFontFamily;
max-height: 0;
overflow: hidden;
&.slow-validate-show {
@include transition(max-height .25s ease-in 2s);
max-height: 10em;
}
}
.visuallyhidden { .visuallyhidden {
position: absolute; position: absolute;
overflow: hidden; overflow: hidden;
......
...@@ -75,6 +75,10 @@ ...@@ -75,6 +75,10 @@
// This is not ideal // This is not ideal
&.ng-dirty.ng-invalid { &.ng-dirty.ng-invalid {
@extend %form-input-error-state; @extend %form-input-error-state;
&.ng-touched ~ .form-error-list {
display: block;
}
} }
} }
...@@ -83,16 +87,10 @@ ...@@ -83,16 +87,10 @@
} }
.form-error-list { .form-error-list {
margin-top: 5px; display: none;
}
.form-field {
& .form-error-list {
display: none;
}
&.form-field-errors .form-error-list { &:first-child {
display: block; margin-top: 5px;
} }
} }
......
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