diff --git a/src/ng/directive/ngRepeat.js b/src/ng/directive/ngRepeat.js
index 11f35c56e84c..f7699b37d7c9 100644
--- a/src/ng/directive/ngRepeat.js
+++ b/src/ng/directive/ngRepeat.js
@@ -219,7 +219,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
}
lhs = match[1];
- rhs = match[2];
+ rhs = $parse(match[2]);
trackByExp = match[3];
if (trackByExp) {
@@ -255,8 +255,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
// - index: position
var lastBlockMap = {};
- //watch props
- $scope.$watchCollection(rhs, function ngRepeatAction(collection){
+ var ngRepeatAction = function(collection){
var index, length,
previousNode = $element[0], // current position of the node
nextNode,
@@ -382,7 +381,11 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
}
}
lastBlockMap = nextBlockMap;
- });
+ };
+
+ ngRepeatAction(rhs($scope));
+ //watch props
+ $scope.$watchCollection(rhs, ngRepeatAction);
}
};
diff --git a/test/ng/directive/ngRepeatSpec.js b/test/ng/directive/ngRepeatSpec.js
index e267e0e9b029..6976b55ee48d 100644
--- a/test/ng/directive/ngRepeatSpec.js
+++ b/test/ng/directive/ngRepeatSpec.js
@@ -142,7 +142,7 @@ describe('ngRepeat', function() {
scope.items = {age:20};
$compile('
')(scope);
scope.$digest();
- expect($exceptionHandler.errors.shift().message).toMatch(/ng:badname/);
+ expect($exceptionHandler.errors.shift()[0].message).toMatch(/ng:badname/);
});
@@ -757,7 +757,7 @@ describe('ngRepeat', function() {
};
});
element = $compile('
')($rootScope);
- expect(element.text()).toBe('');
+ expect(element.text()).toBe('{{i}}{{i}}{{i}}');
$rootScope.$apply();
expect(element.text()).toBe('123');
}));
@@ -1273,3 +1273,279 @@ describe('ngRepeat animations', function() {
);
});
+
+describe('ngRepeat nesting with other directives', function() {
+ var element, expectedCalls, actualCalls, $compile, scope, $exceptionHandler;
+
+ beforeEach(module(function(_$compileProvider_) {
+ actualCalls = [];
+ _$compileProvider_.directive('callLog', valueFn({
+ controller: function($scope, $attrs) {
+ actualCalls.push($attrs.callLog + '-controller');
+ },
+ compile: function compile(element, attrs) {
+ actualCalls.push(attrs.callLog + '-compile');
+ return {
+ pre: function preLink(scope, element, attrs) {
+ actualCalls.push(attrs.callLog + '-preLink');
+ },
+ post: function postLink(scope, element, attrs) {
+ actualCalls.push(attrs.callLog + '-postLink');
+ }
+ };
+ }
+ }));
+ }));
+
+ beforeEach(module(function($exceptionHandlerProvider) {
+ $exceptionHandlerProvider.mode('log');
+ }));
+
+ beforeEach(inject(function(_$compile_, $rootScope, _$exceptionHandler_) {
+ $compile = _$compile_;
+ $exceptionHandler = _$exceptionHandler_;
+ scope = $rootScope.$new();
+ }));
+
+ afterEach(function() {
+ if ($exceptionHandler.errors.length) {
+ dump(jasmine.getEnv().currentSpec.getFullName());
+ dump('$exceptionHandler has errors');
+ dump($exceptionHandler.errors);
+ expect($exceptionHandler.errors).toBe([]);
+ }
+ dealoc(element);
+ });
+
+ it('should preserve directive function call order when collections are empty', function() {
+ expectedCalls = [
+ 'outer-compile',
+ 'middle-compile',
+ 'inner-compile'
+ ];
+ actualCalls = [];
+ scope.outerItems = [];
+ scope.middleItems = [];
+ scope.innerItems = [];
+ element = $compile('')(scope);
+ scope.$digest();
+ expect(actualCalls).toEqual(expectedCalls);
+ });
+
+ it('should preserve directive function call order when outer collection is empty', function() {
+ expectedCalls = [
+ 'outer-compile',
+ 'middle-compile',
+ 'inner-compile'
+ ];
+ actualCalls = [];
+ scope.outerItems = [];
+ scope.middleItems = [1];
+ scope.innerItems = [1];
+ element = $compile('')(scope);
+ scope.$digest();
+ expect(actualCalls).toEqual(expectedCalls);
+ });
+
+ it('should preserve directive function call order when middle collection is empty', function() {
+ expectedCalls = [
+ 'outer-compile',
+ 'middle-compile',
+ 'inner-compile',
+ 'outer-controller',
+ 'outer-preLink',
+ 'outer-postLink'
+ ];
+ actualCalls = [];
+ scope.outerItems = [1];
+ scope.middleItems = [];
+ scope.innerItems = [1];
+ element = $compile('')(scope);
+ scope.$digest();
+ expect(actualCalls).toEqual(expectedCalls);
+ });
+
+ it('should preserve directive function call order when inner collection is empty', function() {
+ expectedCalls = [
+ 'outer-compile',
+ 'middle-compile',
+ 'inner-compile',
+ 'outer-controller',
+ 'outer-preLink',
+ 'middle-controller',
+ 'middle-preLink',
+ 'middle-postLink',
+ 'outer-postLink'
+ ];
+ actualCalls = [];
+ scope.outerItems = [1];
+ scope.middleItems = [1];
+ scope.innerItems = [];
+ element = $compile('')(scope);
+ scope.$digest();
+ expect(actualCalls).toEqual(expectedCalls);
+ });
+
+ it('should preserve directive function call order when collections are not empty', function() {
+ expectedCalls = [
+ 'outer-compile',
+ 'middle-compile',
+ 'inner-compile',
+ 'outer-controller',
+ 'outer-preLink',
+ 'middle-controller',
+ 'middle-preLink',
+ 'inner-controller',
+ 'inner-preLink',
+ 'inner-postLink',
+ 'middle-postLink',
+ 'outer-postLink'
+ ];
+ actualCalls = [];
+ scope.outerItems = [1];
+ scope.middleItems = [1];
+ scope.innerItems = [1];
+ element = $compile('')(scope);
+ scope.$digest();
+ expect(actualCalls).toEqual(expectedCalls);
+ });
+
+ it('should preserve directive function call order when outer collection is modified', function() {
+ scope.outerItems = [1];
+ scope.middleItems = [1];
+ scope.innerItems = [1];
+ element = $compile('')(scope);
+ scope.$digest();
+
+ // GROW
+ expectedCalls = [
+ 'outer-controller',
+ 'outer-preLink',
+ 'middle-controller',
+ 'middle-preLink',
+ 'inner-controller',
+ 'inner-preLink',
+ 'inner-postLink',
+ 'middle-postLink',
+ 'outer-postLink'
+ ];
+ actualCalls = [];
+ scope.outerItems.push(2);
+ scope.$digest();
+ expect(actualCalls).toEqual(expectedCalls);
+
+ // SHRINK
+ expectedCalls = [];
+ actualCalls = [];
+ scope.outerItems.pop();
+ scope.outerItems.shift();
+ scope.$digest();
+ expect(actualCalls).toEqual(expectedCalls);
+ });
+
+ it('should preserve directive function call order when middle collection is modified', function() {
+ scope.outerItems = [1];
+ scope.middleItems = [1];
+ scope.innerItems = [1];
+ element = $compile('')(scope);
+ scope.$digest();
+
+ // GROW
+ expectedCalls = [
+ 'middle-controller',
+ 'middle-preLink',
+ 'inner-controller',
+ 'inner-preLink',
+ 'inner-postLink',
+ 'middle-postLink'
+ ];
+ actualCalls = [];
+ scope.middleItems.push(2);
+ scope.$digest();
+ expect(actualCalls).toEqual(expectedCalls);
+
+ // SHRINK
+ expectedCalls = [];
+ actualCalls = [];
+ scope.middleItems.pop();
+ scope.middleItems.shift();
+ scope.$digest();
+ expect(actualCalls).toEqual(expectedCalls);
+ });
+
+ it('should preserve directive function call order when inner collection is modified', function() {
+ scope.outerItems = [1];
+ scope.middleItems = [1];
+ scope.innerItems = [1];
+ element = $compile('')(scope);
+ scope.$digest();
+
+ // GROW
+ expectedCalls = [
+ 'inner-controller',
+ 'inner-preLink',
+ 'inner-postLink'
+ ];
+ actualCalls = [];
+ scope.innerItems.push(2);
+ scope.$digest();
+ expect(actualCalls).toEqual(expectedCalls);
+
+ // SHRINK
+ expectedCalls = [];
+ actualCalls = [];
+ scope.innerItems.pop();
+ scope.innerItems.shift();
+ scope.$digest();
+ expect(actualCalls).toEqual(expectedCalls);
+ });
+
+});