Skip to content

Commit 46e10e1

Browse files
committed
fix(select): add basic track by and select as support
Instead of throwing an error when using "track by" and "select as" expressions, ngOptions will assume that the track by expression is valid, and will use it to compare values. Closes angular#6564
1 parent b90f5e5 commit 46e10e1

File tree

2 files changed

+36
-19
lines changed

2 files changed

+36
-19
lines changed

src/ng/directive/select.js

+5-11
Original file line numberDiff line numberDiff line change
@@ -363,13 +363,6 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
363363
//re-usable object to represent option's locals
364364
locals = {};
365365

366-
if (trackFn && selectAsFn) {
367-
throw ngOptionsMinErr('trkslct',
368-
"Comprehension expression cannot contain both selectAs '{0}' " +
369-
"and trackBy '{1}' expressions.",
370-
selectAs, track);
371-
}
372-
373366
if (nullOption) {
374367
// compile the element since there might be bindings in it
375368
$compile(nullOption)(scope);
@@ -470,15 +463,16 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
470463
} else {
471464
selectedSet = new HashMap(viewValue);
472465
}
473-
} else if (!selectAsFn && trackFn) {
466+
} else if (trackFn) {
474467
viewValue = callExpression(trackFn, null, viewValue);
475468
}
469+
476470
return function isSelected(key, value) {
477471
var compareValueFn;
478-
if (selectAsFn) {
479-
compareValueFn = selectAsFn;
480-
} else if (trackFn) {
472+
if (trackFn) {
481473
compareValueFn = trackFn;
474+
} else if (selectAsFn) {
475+
compareValueFn = selectAsFn;
482476
} else {
483477
compareValueFn = valueFn;
484478
}

test/ng/directive/selectSpec.js

+31-8
Original file line numberDiff line numberDiff line change
@@ -819,20 +819,43 @@ describe('select', function() {
819819

820820
describe('selectAs+trackBy expression', function() {
821821
beforeEach(function() {
822-
scope.arr = [{id: 10, label: 'ten'}, {id:'20', label: 'twenty'}];
822+
scope.arr = [{subItem: {label: 'ten', id: 10}}, {subItem: {label: 'twenty', id: 20}}];
823823
scope.obj = {'10': {score: 10, label: 'ten'}, '20': {score: 20, label: 'twenty'}};
824824
});
825825

826826

827-
it('should throw a helpful minerr', function() {
828-
expect(function() {
827+
it('should bind to scope value through experession while tracking/identifying objects', function() {
828+
createSelect({
829+
'ng-model': 'selected',
830+
'ng-options': 'item.subItem as item.name for item in arr track by (item.id || item.subItem.id)'
831+
});
832+
833+
scope.$apply(function() {
834+
scope.selected = scope.arr[0].subItem;
835+
});
836+
expect(element.val()).toEqual('0');
837+
838+
scope.$apply(function() {
839+
scope.selected = scope.arr[1].subItem;
840+
});
841+
expect(element.val()).toEqual('1');
842+
843+
// Now test val() -> model
844+
845+
element.val('0');
846+
browserTrigger(element, 'change');
847+
expect(scope.selected).toBe(scope.arr[0].subItem);
829848

830-
createSelect({
831-
'ng-model': 'selected',
832-
'ng-options': 'item.id as item.name for item in values track by item.id'
833-
});
834849

835-
}).toThrowMinErr('ngOptions', 'trkslct', "Comprehension expression cannot contain both selectAs 'item.id' and trackBy 'item.id' expressions.");
850+
scope.$apply(function() {
851+
scope.arr[1] = {subItem: {label: 'new item', id: 20}};
852+
scope.selected = scope.arr[1];
853+
});
854+
expect(element.val()).toBe('1')
855+
856+
element.val('1');
857+
browserTrigger(element, 'change');
858+
expect(scope.selected).toBe(scope.arr[1].subItem);
836859
});
837860
});
838861

0 commit comments

Comments
 (0)