aboutsummaryrefslogtreecommitdiffstats
path: root/src/widget/select.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/widget/select.js')
-rw-r--r--src/widget/select.js138
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
});
}