diff options
Diffstat (limited to 'src/widget/select.js')
| -rw-r--r-- | src/widget/select.js | 138 |
1 files changed, 67 insertions, 71 deletions
diff --git a/src/widget/select.js b/src/widget/select.js index f70575a6..e7386147 100644 --- a/src/widget/select.js +++ b/src/widget/select.js @@ -123,87 +123,79 @@ */ var ngOptionsDirective = valueFn({ terminal: true }); -var selectDirective = ['$formFactory', '$compile', '$parse', - function($formFactory, $compile, $parse){ +var selectDirective = ['$compile', '$parse', function($compile, $parse) { //00001111100000000000222200000000000000000000003333000000000000044444444444444444000000000555555555555555550000000666666666666666660000000000000007777 var NG_OPTIONS_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w\d]*)|(?:\(\s*([\$\w][\$\w\d]*)\s*,\s*([\$\w][\$\w\d]*)\s*\)))\s+in\s+(.*)$/; return { restrict: 'E', - link: function(modelScope, selectElement, attr) { - if (!attr.ngModel) return; - var form = $formFactory.forElement(selectElement), - multiple = attr.multiple, - optionsExp = attr.ngOptions, - modelExp = attr.ngModel, - widget = form.$createWidget({ - scope: modelScope, - model: modelExp, - onChange: attr.ngChange, - alias: attr.name, - controller: ['$scope', optionsExp ? Options : (multiple ? Multiple : Single)]}); - - selectElement.bind('$destroy', function() { widget.$destroy(); }); - - widget.$pristine = !(widget.$dirty = false); - - widget.$on('$validate', function() { - var valid = !attr.required || !!widget.$modelValue; - if (valid && multiple && attr.required) valid = !!widget.$modelValue.length; - if (valid !== !widget.$error.REQUIRED) { - widget.$emit(valid ? '$valid' : '$invalid', 'REQUIRED'); - } - }); + require: '?ngModel', + link: function(scope, element, attr, ctrl) { + if (!ctrl) return; + + var multiple = attr.multiple, + optionsExp = attr.ngOptions; + + // required validator + if (multiple && (attr.required || attr.ngRequired)) { + var requiredValidator = function(value) { + ctrl.emitValidity('REQUIRED', !attr.required || (value && value.length)); + return value; + }; - widget.$on('$viewChange', function() { - widget.$pristine = !(widget.$dirty = true); - }); + ctrl.parsers.push(requiredValidator); + ctrl.formatters.unshift(requiredValidator); - forEach(['valid', 'invalid', 'pristine', 'dirty'], function(name) { - widget.$watch('$' + name, function(value) { - selectElement[value ? 'addClass' : 'removeClass']('ng-' + name); + attr.$observe('required', function() { + requiredValidator(ctrl.viewValue); }); - }); + } + + if (optionsExp) Options(scope, element, ctrl); + else if (multiple) Multiple(scope, element, ctrl); + else Single(scope, element, ctrl); + //////////////////////////// - function Multiple(widget) { - widget.$render = function() { - var items = new HashMap(this.$viewValue); - forEach(selectElement.children(), function(option){ - option.selected = isDefined(items.get(option.value)); - }); + + + function Single(scope, selectElement, ctrl) { + ctrl.render = function() { + selectElement.val(ctrl.viewValue); }; selectElement.bind('change', function() { - widget.$apply(function() { - var array = []; - forEach(selectElement.children(), function(option){ - if (option.selected) { - array.push(option.value); - } - }); - widget.$emit('$viewChange', array); + scope.$apply(function() { + ctrl.touch(); + ctrl.read(selectElement.val()); }); }); - } - function Single(widget) { - widget.$render = function() { - selectElement.val(widget.$viewValue); + function Multiple(scope, selectElement, ctrl) { + ctrl.render = function() { + var items = new HashMap(ctrl.viewValue); + forEach(selectElement.children(), function(option) { + option.selected = isDefined(items.get(option.value)); + }); }; selectElement.bind('change', function() { - widget.$apply(function() { - widget.$emit('$viewChange', selectElement.val()); + scope.$apply(function() { + var array = []; + forEach(selectElement.children(), function(option) { + if (option.selected) { + array.push(option.value); + } + }); + ctrl.touch(); + ctrl.read(array); }); }); - - widget.$viewValue = selectElement.val(); } - function Options(widget) { + function Options(scope, selectElement, ctrl) { var match; if (! (match = optionsExp.match(NG_OPTIONS_REGEXP))) { @@ -234,15 +226,15 @@ var selectDirective = ['$formFactory', '$compile', '$parse', // developer declared null option, so user should be able to select it nullOption = jqLite(option).remove(); // compile the element since there might be bindings in it - $compile(nullOption)(modelScope); + $compile(nullOption)(scope); } }); selectElement.html(''); // clear contents selectElement.bind('change', function() { - widget.$apply(function() { + scope.$apply(function() { var optionGroup, - collection = valuesFn(modelScope) || [], + collection = valuesFn(scope) || [], locals = {}, key, value, optionElement, index, groupIndex, length, groupLength; @@ -259,7 +251,7 @@ var selectDirective = ['$formFactory', '$compile', '$parse', key = optionElement.val(); if (keyName) locals[keyName] = key; locals[valueName] = collection[key]; - value.push(valueFn(modelScope, locals)); + value.push(valueFn(scope, locals)); } } } @@ -272,17 +264,21 @@ var selectDirective = ['$formFactory', '$compile', '$parse', } else { locals[valueName] = collection[key]; if (keyName) locals[keyName] = key; - value = valueFn(modelScope, locals); + value = valueFn(scope, locals); } } - if (isDefined(value) && modelScope.$viewVal !== value) { - widget.$emit('$viewChange', value); + ctrl.touch(); + + if (ctrl.viewValue !== value) { + ctrl.read(value); } }); }); - widget.$watch(render); - widget.$render = render; + ctrl.render = render; + + // TODO(vojta): can't we optimize this ? + scope.$watch(render); function render() { var optionGroups = {'':[]}, // Temporary location for the option groups before we render them @@ -291,8 +287,8 @@ var selectDirective = ['$formFactory', '$compile', '$parse', optionGroup, option, existingParent, existingOptions, existingOption, - modelValue = widget.$modelValue, - values = valuesFn(modelScope) || [], + modelValue = ctrl.modelValue, + values = valuesFn(scope) || [], keys = keyName ? sortedKeys(values) : values, groupLength, length, groupIndex, index, @@ -313,20 +309,20 @@ var selectDirective = ['$formFactory', '$compile', '$parse', // We now build up the list of options we need (we merge later) for (index = 0; length = keys.length, index < length; index++) { locals[valueName] = values[keyName ? locals[keyName]=keys[index]:index]; - optionGroupName = groupByFn(modelScope, locals) || ''; + optionGroupName = groupByFn(scope, locals) || ''; if (!(optionGroup = optionGroups[optionGroupName])) { optionGroup = optionGroups[optionGroupName] = []; optionGroupNames.push(optionGroupName); } if (multiple) { - selected = selectedSet.remove(valueFn(modelScope, locals)) != undefined; + selected = selectedSet.remove(valueFn(scope, locals)) != undefined; } else { - selected = modelValue === valueFn(modelScope, locals); + selected = modelValue === valueFn(scope, locals); selectedSet = selectedSet || selected; // see if at least one item is selected } optionGroup.push({ id: keyName ? keys[index] : index, // either the index into array or key from object - label: displayFn(modelScope, locals) || '', // what will be seen by the user + label: displayFn(scope, locals) || '', // what will be seen by the user selected: selected // determine if we should be selected }); } |
