aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ng/directive/select.js60
1 files changed, 48 insertions, 12 deletions
diff --git a/src/ng/directive/select.js b/src/ng/directive/select.js
index 4f4aace2..7a1cab53 100644
--- a/src/ng/directive/select.js
+++ b/src/ng/directive/select.js
@@ -39,7 +39,7 @@
* * `label` **`for`** `value` **`in`** `array`
* * `select` **`as`** `label` **`for`** `value` **`in`** `array`
* * `label` **`group by`** `group` **`for`** `value` **`in`** `array`
- * * `select` **`as`** `label` **`group by`** `group` **`for`** `value` **`in`** `array`
+ * * `select` **`as`** `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
* * for object data sources:
* * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
* * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
@@ -59,6 +59,9 @@
* element. If not specified, `select` expression will default to `value`.
* * `group`: The result of this expression will be used to group options using the `<optgroup>`
* DOM element.
+ * * `trackexpr`: Used when working with an array of objects. The result of this expression will be
+ * used to identify the objects in the array. The `trackexpr` will most likely refer to the
+ * `value` variable (e.g. `value.propertyName`).
*
* @example
<doc:example>
@@ -123,8 +126,8 @@
var ngOptionsDirective = valueFn({ terminal: true });
var selectDirective = ['$compile', '$parse', function($compile, $parse) {
- //0000111110000000000022220000000000000000000000333300000000000000444444444444444440000000005555555555555555500000006666666666666666600000000000000077770
- 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+(.*)$/,
+ //0000111110000000000022220000000000000000000000333300000000000000444444444444444440000000005555555555555555500000006666666666666666600000000000000007777000000000000000000088888
+ 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+(.*?)(?:\s+track\s+by\s+(.*?))?$/,
nullModelCtrl = {$setViewValue: noop};
return {
@@ -298,7 +301,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
if (! (match = optionsExp.match(NG_OPTIONS_REGEXP))) {
throw Error(
- "Expected ngOptions in form of '_select_ (as _label_)? for (_key_,)?_value_ in _collection_'" +
+ "Expected ngOptions in form of '_select_ (as _label_)? for (_key_,)?_value_ in _collection_ (track by _expr_)?'" +
" but got '" + optionsExp + "'.");
}
@@ -308,6 +311,8 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
groupByFn = $parse(match[3] || ''),
valueFn = $parse(match[2] ? match[1] : valueName),
valuesFn = $parse(match[7]),
+ track = match[8],
+ trackFn = track ? $parse(match[8]) : null,
// This is an array of array of existing option groups in DOM. We try to reuse these if possible
// optionGroupsCache[0] is the options with no option group
// optionGroupsCache[?][0] is the parent: either the SELECT or OPTGROUP element
@@ -348,7 +353,14 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
if ((optionElement = optionGroup[index].element)[0].selected) {
key = optionElement.val();
if (keyName) locals[keyName] = key;
- locals[valueName] = collection[key];
+ if (trackFn) {
+ for (var trackIndex = 0; trackIndex < collection.length; trackIndex++) {
+ locals[valueName] = collection[trackIndex];
+ if (trackFn(scope, locals) == key) break;
+ }
+ } else {
+ locals[valueName] = collection[key];
+ }
value.push(valueFn(scope, locals));
}
}
@@ -360,9 +372,19 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
} else if (key == ''){
value = null;
} else {
- locals[valueName] = collection[key];
- if (keyName) locals[keyName] = key;
- value = valueFn(scope, locals);
+ if (trackFn) {
+ for (var trackIndex = 0; trackIndex < collection.length; trackIndex++) {
+ locals[valueName] = collection[trackIndex];
+ if (trackFn(scope, locals) == key) {
+ value = valueFn(scope, locals);
+ break;
+ }
+ }
+ } else {
+ locals[valueName] = collection[key];
+ if (keyName) locals[keyName] = key;
+ value = valueFn(scope, locals);
+ }
}
}
ctrl.$setViewValue(value);
@@ -394,7 +416,15 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
label;
if (multiple) {
- selectedSet = new HashMap(modelValue);
+ if (trackFn && isArray(modelValue)) {
+ selectedSet = new HashMap([]);
+ for (var trackIndex = 0; trackIndex < modelValue.length; trackIndex++) {
+ locals[valueName] = modelValue[trackIndex];
+ selectedSet.put(trackFn(scope, locals), modelValue[trackIndex]);
+ }
+ } else {
+ selectedSet = new HashMap(modelValue);
+ }
}
// We now build up the list of options we need (we merge later)
@@ -406,15 +436,21 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
optionGroupNames.push(optionGroupName);
}
if (multiple) {
- selected = selectedSet.remove(valueFn(scope, locals)) != undefined;
+ selected = selectedSet.remove(trackFn ? trackFn(scope, locals) : valueFn(scope, locals)) != undefined;
} else {
- selected = modelValue === valueFn(scope, locals);
+ if (trackFn) {
+ var modelCast = {};
+ modelCast[valueName] = modelValue;
+ selected = trackFn(scope, modelCast) === trackFn(scope, locals);
+ } else {
+ selected = modelValue === valueFn(scope, locals);
+ }
selectedSet = selectedSet || selected; // see if at least one item is selected
}
label = displayFn(scope, locals); // what will be seen by the user
label = label === undefined ? '' : label; // doing displayFn(scope, locals) || '' overwrites zero values
optionGroup.push({
- id: keyName ? keys[index] : index, // either the index into array or key from object
+ id: trackFn ? trackFn(scope, locals) : (keyName ? keys[index] : index), // either the index into array or key from object
label: label,
selected: selected // determine if we should be selected
});