From 904b69c745ea4afc1d6ecd2a5f3138c6f947b157 Mon Sep 17 00:00:00 2001 From: Igor Minar Date: Wed, 18 Apr 2012 00:48:25 -0700 Subject: fix(select): properly handle empty & unknown options without ngOptions Previously only when ngOptions was used, we correctly handled situations when model was set to an unknown value. With this change, we'll add/remove extra unknown option or reuse an existing empty option (option with value set to "") when model is undefined. --- src/ng/directive/select.js | 204 +++++++++++++++++++++++++++++++++------------ 1 file changed, 150 insertions(+), 54 deletions(-) (limited to 'src') diff --git a/src/ng/directive/select.js b/src/ng/directive/select.js index 49137b33..aa540828 100644 --- a/src/ng/directive/select.js +++ b/src/ng/directive/select.js @@ -22,16 +22,10 @@ * be nested into the `
Color (null allowed): -
+ -

+
Color grouped by shade: and IE barfs otherwise. + optionTemplate = jqLite(document.createElement('option')), + optGroupTemplate =jqLite(document.createElement('optgroup')), + unknownOption = optionTemplate.clone(); + + // find "null" option + for(var i = 0, children = element.children(), ii = children.length; i < ii; i++) { + if (children[i].value == '') { + emptyOption = nullOption = children.eq(i); + break; + } + } + + selectCtrl.init(ngModelCtrl, nullOption, unknownOption); // required validator if (multiple && (attr.required || attr.ngRequired)) { var requiredValidator = function(value) { - ctrl.$setValidity('required', !attr.required || (value && value.length)); + ngModelCtrl.$setValidity('required', !attr.required || (value && value.length)); return value; }; - ctrl.$parsers.push(requiredValidator); - ctrl.$formatters.unshift(requiredValidator); + ngModelCtrl.$parsers.push(requiredValidator); + ngModelCtrl.$formatters.unshift(requiredValidator); attr.$observe('required', function() { - requiredValidator(ctrl.$viewValue); + requiredValidator(ngModelCtrl.$viewValue); }); } - if (optionsExp) Options(scope, element, ctrl); - else if (multiple) Multiple(scope, element, ctrl); - else Single(scope, element, ctrl); + if (optionsExp) Options(scope, element, ngModelCtrl); + else if (multiple) Multiple(scope, element, ngModelCtrl); + else Single(scope, element, ngModelCtrl, selectCtrl); //////////////////////////// - function Single(scope, selectElement, ctrl) { - ctrl.$render = function() { - selectElement.val(ctrl.$viewValue); + function Single(scope, selectElement, ngModelCtrl, selectCtrl) { + ngModelCtrl.$render = function() { + var viewValue = ngModelCtrl.$viewValue; + + if (selectCtrl.hasOption(viewValue)) { + if (unknownOption.parent()) unknownOption.remove(); + selectElement.val(viewValue); + if (viewValue === '') emptyOption.prop('selected', true); // to make IE9 happy + } else { + if (isUndefined(viewValue) && emptyOption) { + selectElement.val(''); + } else { + selectCtrl.renderUnknownOption(viewValue); + } + } }; selectElement.bind('change', function() { scope.$apply(function() { - ctrl.$setViewValue(selectElement.val()); + if (unknownOption.parent()) unknownOption.remove(); + ngModelCtrl.$setViewValue(selectElement.val()); }); }); } @@ -219,26 +300,26 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) { groupByFn = $parse(match[3] || ''), valueFn = $parse(match[2] ? match[1] : valueName), valuesFn = $parse(match[7]), - // we can't just jqLite('