fix(ngRepeat): ensure that the correct (transcluded) scope is used

This commit is contained in:
Peter Bacon Darwin
2014-05-23 11:45:03 +01:00
committed by Vojta Jina
parent d71df9f83c
commit b87e5fc092
2 changed files with 34 additions and 19 deletions

View File

@@ -264,7 +264,6 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
// lastBlockMap on the next iteration.
nextBlockMap = {},
arrayLength,
childScope,
key, value, // key/value of iteration
trackById,
trackByIdFn,
@@ -273,6 +272,17 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
nextBlockOrder = [],
elementsToRemove;
var updateScope = function(scope, index) {
scope[valueIdentifier] = value;
if (keyIdentifier) scope[keyIdentifier] = key;
scope.$index = index;
scope.$first = (index === 0);
scope.$last = (index === (arrayLength - 1));
scope.$middle = !(scope.$first || scope.$last);
// jshint bitwise: false
scope.$odd = !(scope.$even = (index&1) === 0);
// jshint bitwise: true
};
if (isArrayLike(collection)) {
collectionKeys = collection;
@@ -340,8 +350,6 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
if (block.scope) {
// if we have already seen this object, then we need to reuse the
// associated scope/element
childScope = block.scope;
nextNode = previousNode;
do {
nextNode = nextNode.nextSibling;
@@ -354,25 +362,11 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
previousNode = getBlockEnd(block);
} else {
// new item which we don't know about
childScope = $scope.$new();
}
childScope[valueIdentifier] = value;
if (keyIdentifier) childScope[keyIdentifier] = key;
childScope.$index = index;
childScope.$first = (index === 0);
childScope.$last = (index === (arrayLength - 1));
childScope.$middle = !(childScope.$first || childScope.$last);
// jshint bitwise: false
childScope.$odd = !(childScope.$even = (index&1) === 0);
// jshint bitwise: true
if (!block.scope) {
$transclude(childScope, function(clone) {
$transclude(function(clone, scope) {
block.scope = scope;
clone[clone.length++] = document.createComment(' end ngRepeat: ' + expression + ' ');
$animate.enter(clone, null, jqLite(previousNode));
previousNode = clone;
block.scope = childScope;
// Note: We only need the first/last node of the cloned nodes.
// However, we need to keep the reference to the jqlite wrapper as it might be changed later
// by a directive with templateUrl when it's template arrives.
@@ -380,6 +374,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
nextBlockMap[block.id] = block;
});
}
updateScope(block.scope, index);
}
lastBlockMap = nextBlockMap;
});

View File

@@ -1175,6 +1175,26 @@ describe('ngRepeat and transcludes', function() {
dealoc(element);
});
});
it('should use the correct transcluded scope', function() {
module(function($compileProvider) {
$compileProvider.directive('iso', valueFn({
restrict: 'E',
transclude: true,
template: '<div ng-repeat="a in [1]"><div ng-transclude></div></div>',
scope: {}
}));
});
inject(function($compile, $rootScope) {
$rootScope.val = 'transcluded content';
var element = $compile('<iso><span ng-bind="val"></span></iso>')($rootScope);
$rootScope.$digest();
expect(trim(element.text())).toEqual('transcluded content');
dealoc(element);
});
});
});
describe('ngRepeat animations', function() {