Skip to content

Commit c3cbea7

Browse files
committed
fix(ngRepeat): support complex assignable aliasAs expressions
Parse aliasAs as an expression, and assert that the expression is assignable. BREAKING CHANGE Previously, any name passed as an expression would make up a single property name, including constant values such as 1, NaN, null, undefined, or even expressions such as function calls or boolean expressions. Now, more complex expressions are possible, allowing the collection alias to be assigned as a property of an object --- however, if the expression is not determined to be assignable, it will throw. Fixes angular#8438
1 parent 0107bfc commit c3cbea7

File tree

3 files changed

+81
-2
lines changed

3 files changed

+81
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
@ngdoc error
2+
@name ngRepeat:nonassign
3+
@fullName Non-assignable Expression
4+
@description
5+
6+
Occurs when there is a syntax error in an {@link ng.directive:ngRepeat ngRepeat} expression which is expected to be assignable.=
7+
8+
The {@link ng.directive:ngRepeat ngRepeat} directive's `alias as` syntax is used to assign an alias for the processed collection in scope.
9+
10+
If the expression is not assignable (such as a literal value or a function call or comparison operation), the expression is unassignable.

src/ng/directive/ngRepeat.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -232,9 +232,13 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
232232

233233
lhs = match[1];
234234
rhs = match[2];
235-
aliasAs = match[3];
235+
aliasAs = match[3] && $parse(match[3]);
236236
trackByExp = match[4];
237237

238+
if (aliasAs && !aliasAs.assign) {
239+
throw ngRepeatMinErr('nonassign', "Expected collection alias to be an assignable expression but got '{0}'.", match[3]);
240+
}
241+
238242
if (trackByExp) {
239243
trackByExpGetter = $parse(trackByExp);
240244
trackByIdExpFn = function(key, value, index) {
@@ -286,7 +290,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
286290
elementsToRemove;
287291

288292
if (aliasAs) {
289-
$scope[aliasAs] = collection;
293+
aliasAs.assign($scope, collection);
290294
}
291295

292296
var updateScope = function(scope, index) {

test/ng/directive/ngRepeatSpec.js

+65
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,71 @@ describe('ngRepeat', function() {
424424

425425
expect(trim(element.text())).toEqual('No results found...');
426426
});
427+
428+
429+
it('should support complex assignable expressions', function() {
430+
element = $compile(
431+
'<div>' +
432+
' <div ng-repeat="item in items | filter:x as ngRepeat.results track by $index">{{item}}</div>' +
433+
'</div>')(scope);
434+
435+
scope.x = 'bl';
436+
scope.items = [
437+
{ name : 'red' },
438+
{ name : 'blue' },
439+
{ name : 'green' },
440+
{ name : 'black' },
441+
{ name : 'orange' },
442+
{ name : 'blonde' }
443+
];
444+
scope.$digest();
445+
expect(scope.ngRepeat).toEqual({
446+
results: [
447+
{ name : 'blue' },
448+
{ name : 'black' },
449+
{ name : 'blonde' }
450+
]
451+
});
452+
});
453+
454+
455+
it('should throw if expression is not assignable', inject(function($exceptionHandler) {
456+
element = $compile(
457+
'<div>' +
458+
' <div ng-repeat="item in items | filter:x as null track by $index">{{item}}</div>' +
459+
'</div>')(scope);
460+
461+
scope.x = 'bl';
462+
scope.items = [
463+
{ name : 'red' },
464+
{ name : 'blue' },
465+
{ name : 'green' },
466+
{ name : 'black' },
467+
{ name : 'orange' },
468+
{ name : 'blonde' }
469+
];
470+
471+
expect($exceptionHandler.errors.shift()[0].message).
472+
toMatch(/^\[ngRepeat:nonassign\] Expected collection alias to be an assignable expression but got \'null\'\./);
473+
}));
474+
475+
476+
it('should throw if alias as expression is an assignment expression', inject(function($exceptionHandler) {
477+
element = $compile(
478+
'<div>' +
479+
' <div ng-repeat="item in items | filter:x as foo=6 track by $index">{{item}}</div>' +
480+
'</div>')(scope);
481+
expect($exceptionHandler.errors.shift()[0].message).
482+
toMatch(/^\[ngRepeat:nonassign\] Expected collection alias to be an assignable expression but got \'foo=6\'\./);
483+
dealoc(element);
484+
485+
element = $compile(
486+
'<div>' +
487+
' <div ng-repeat="item in items | filter:x as foo = 6 track by $index">{{item}}</div>' +
488+
'</div>')(scope);
489+
expect($exceptionHandler.errors.shift()[0].message).
490+
toMatch(/^\[ngRepeat:nonassign\] Expected collection alias to be an assignable expression but got \'foo = 6\'\./);
491+
}));
427492
});
428493

429494

0 commit comments

Comments
 (0)