Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

Commit

Permalink
fix(compiler): corrects component transclusion on compilation root.
Browse files Browse the repository at this point in the history
Closes# 2155
  • Loading branch information
IgorMinar authored and mhevery committed Jun 28, 2013
1 parent 344e195 commit 15e1a29
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 13 deletions.
20 changes: 13 additions & 7 deletions src/ng/compile.js
Original file line number Diff line number Diff line change
Expand Up @@ -749,7 +749,7 @@ function $CompileProvider($provide) {
newTemplateAttrs
)
);
mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
mergeTemplateAttributes(templateAttrs, newTemplateAttrs, directive.name);

ii = directives.length;
} else {
Expand Down Expand Up @@ -1007,15 +1007,16 @@ function $CompileProvider($provide) {
*
* @param {object} dst destination attributes (original DOM)
* @param {object} src source attributes (from the directive template)
* @param {string} ignoreName attribute which should be ignored
*/
function mergeTemplateAttributes(dst, src) {
function mergeTemplateAttributes(dst, src, ignoreName) {
var srcAttr = src.$attr,
dstAttr = dst.$attr,
$element = dst.$$element;

// reapply the old attributes to the new element
forEach(dst, function(value, key) {
if (key.charAt(0) != '$') {
if (key.charAt(0) != '$' && key != ignoreName) {
if (src[key]) {
value += (key === 'style' ? ';' : ' ') + src[key];
}
Expand All @@ -1030,7 +1031,7 @@ function $CompileProvider($provide) {
dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value;
} else if (key == 'style') {
$element.attr('style', $element.attr('style') + ';' + value);
} else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) {
} else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key) && key != ignoreName) {
dst[key] = value;
dstAttr[key] = srcAttr[key];
}
Expand Down Expand Up @@ -1073,14 +1074,19 @@ function $CompileProvider($provide) {
tempTemplateAttrs = {$attr: {}};
replaceWith($rootElement, $compileNode, compileNode);
collectDirectives(compileNode, directives, tempTemplateAttrs);
mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
mergeTemplateAttributes(tAttrs, tempTemplateAttrs, origAsyncDirective.name);
} else {
compileNode = beforeTemplateCompileNode;
$compileNode.html(content);
}

directives.unshift(derivedSyncDirective);
afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs, childTranscludeFn);
afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs, childTranscludeFn, $compileNode);
forEach($rootElement, function(node, i) {
if (node == compileNode) {
$rootElement[i] = $compileNode[0];
}
});
afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);


Expand All @@ -1089,7 +1095,7 @@ function $CompileProvider($provide) {
beforeTemplateLinkNode = linkQueue.shift(),
linkRootElement = linkQueue.shift(),
controller = linkQueue.shift(),
linkNode = compileNode;
linkNode = $compileNode[0];

if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
// it was cloned therefore we have to clone as well.
Expand Down
10 changes: 5 additions & 5 deletions test/ng/compileSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,7 @@ describe('$compile', function() {
expect(div.hasClass('log')).toBe(true);
expect(div.css('width')).toBe('10px');
expect(div.css('height')).toBe('20px');
expect(div.attr('replace')).toEqual('');
expect(div.attr('replace')).toEqual(undefined);
expect(div.attr('high-log')).toEqual('');
}));

Expand Down Expand Up @@ -856,7 +856,7 @@ describe('$compile', function() {
$rootScope.$digest();

expect(sortedHtml(element)).
toEqual('<div><b class="hello"><span replace="">Hello, Elvis!</span></b></div>');
toEqual('<div><b class="hello"><span>Hello, Elvis!</span></b></div>');
}));


Expand All @@ -868,7 +868,7 @@ describe('$compile', function() {
$rootScope.$digest();

expect(sortedHtml(element)).
toEqual('<span replace="">Hello, Elvis!</span>');
toEqual('<span>Hello, Elvis!</span>');
}));


Expand Down Expand Up @@ -1077,7 +1077,7 @@ describe('$compile', function() {

var div = element.find('div');
expect(div.attr('i-first')).toEqual('');
expect(div.attr('i-second')).toEqual('');
expect(div.attr('i-second')).toEqual(undefined);
expect(div.attr('i-third')).toEqual('');
expect(div.attr('i-last')).toEqual('');

Expand Down Expand Up @@ -1127,7 +1127,7 @@ describe('$compile', function() {

var div = element.find('div');
expect(div.attr('i-first')).toEqual('');
expect(div.attr('i-second')).toEqual('');
expect(div.attr('i-second')).toEqual(undefined);
expect(div.attr('i-third')).toEqual('');
expect(div.attr('i-last')).toEqual('');

Expand Down
95 changes: 94 additions & 1 deletion test/ng/directive/ngRepeatSpec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
'use strict';

describe('ngRepeat', function() {
var element, $compile, scope, $exceptionHandler;
var element, $compile, scope, $exceptionHandler, $compileProvider;

beforeEach(module(function(_$compileProvider_) {
$compileProvider = _$compileProvider_;
}));


beforeEach(module(function($exceptionHandlerProvider) {
Expand Down Expand Up @@ -448,6 +452,95 @@ describe('ngRepeat', function() {
});


describe('nesting in replaced directive templates', function() {

it('should work when placed on a root element of attr directive with SYNC replaced template',
inject(function($templateCache, $compile, $rootScope) {
$compileProvider.directive('replaceMeWithRepeater', function() {
return {
replace: true,
template: '<span ng-repeat="i in items">{{log(i)}}</span>'
}
});
element = jqLite('<span replace-me-with-repeater></span>');
$compile(element)($rootScope);
expect(element.text()).toBe('');
var logs = [];
$rootScope.log = function(t) { logs.push(t); };

// This creates one item, but it has no parent so we can't get to it
$rootScope.items = [1, 2];
$rootScope.$apply();

// This cleans up to prevent memory leak
$rootScope.items = [];
$rootScope.$apply();
expect(angular.mock.dump(element)).toBe('<!-- ngRepeat: i in items -->');
expect(logs).toEqual([1, 2, 1, 2]);
}));


iit('should work when placed on a root element of attr directive with ASYNC replaced template',

This comment has been minimized.

Copy link
@petebacondarwin

petebacondarwin Jun 28, 2013

Contributor

Need to remove this iit

inject(function($templateCache, $compile, $rootScope) {
$compileProvider.directive('replaceMeWithRepeater', function() {
return {
replace: true,
templateUrl: 'replace-me-with-repeater.html'
}

This comment has been minimized.

Copy link
@petebacondarwin

petebacondarwin Jun 28, 2013

Contributor

Missing semi-colon

});
$templateCache.put('replace-me-with-repeater.html', '<div ng-repeat="i in items">{{log(i)}}</div>');
element = jqLite('<span>-</span><span replace-me-with-repeater></span><span>-</span>');
$compile(element)($rootScope);
expect(element.text()).toBe('--');
var logs = [];
$rootScope.log = function(t) { logs.push(t); };

// This creates one item, but it has no parent so we can't get to it
$rootScope.items = [1, 2];
$rootScope.$apply();

// This cleans up to prevent memory leak
$rootScope.items = [];
$rootScope.$apply();
expect(sortedHtml(element)).toBe('<span>-</span><!-- ngRepeat: i in items --><span>-</span>');
expect(logs).toEqual([1, 2, 1, 2]);
}));


it('should work when placed on a root element of element directive with SYNC replaced template',
inject(function($templateCache, $compile, $rootScope) {
$compileProvider.directive('replaceMeWithRepeater', function() {
return {
restrict: 'E',
replace: true,
template: '<div ng-repeat="i in [1,2,3]">{{i}}</div>'
}

This comment has been minimized.

Copy link
@petebacondarwin

petebacondarwin Jun 28, 2013

Contributor

semi colons...

});
element = $compile('<div><replace-me-with-repeater></replace-me-with-repeater></div>')($rootScope);
expect(element.text()).toBe('');
$rootScope.$apply();
expect(element.text()).toBe('123');
}));


it('should work when placed on a root element of element directive with ASYNC replaced template',
inject(function($templateCache, $compile, $rootScope) {
$compileProvider.directive('replaceMeWithRepeater', function() {
return {
restrict: 'E',
replace: true,
templateUrl: 'replace-me-with-repeater.html'
}
});
$templateCache.put('replace-me-with-repeater.html', '<div ng-repeat="i in [1,2,3]">{{i}}</div>');
element = $compile('<div><replace-me-with-repeater></replace-me-with-repeater></div>')($rootScope);
expect(element.text()).toBe('');
$rootScope.$apply();
expect(element.text()).toBe('123');
}));
});


describe('stability', function() {
var a, b, c, d, lis;

Expand Down

0 comments on commit 15e1a29

Please sign in to comment.