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

Commit 78b9f61

Browse files
gkalpakNarretz
authored andcommitted
fix($compile): support transcluding multi-element directives
Previously, transcluding multi-element directives (e.g. `foo-start`/`foo-end`) was not supported on elements with multi-slot transclusion (a `uterdir` error was thrown). This commit fixes it by putting the transcluded nodes into a DocumentFragment, where they can be traversed via `.nextSibling`. Fixes #15554 Closes #15555
1 parent b9f19ad commit 78b9f61

File tree

2 files changed

+51
-5
lines changed

2 files changed

+51
-5
lines changed

src/ng/compile.js

+7-5
Original file line numberDiff line numberDiff line change
@@ -2575,7 +2575,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
25752575

25762576
// We have transclusion slots,
25772577
// collect them up, compile them and store their transclusion functions
2578-
$template = [];
2578+
$template = window.document.createDocumentFragment();
25792579

25802580
var slotMap = createMap();
25812581
var filledSlots = createMap();
@@ -2603,10 +2603,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
26032603
var slotName = slotMap[directiveNormalize(nodeName_(node))];
26042604
if (slotName) {
26052605
filledSlots[slotName] = true;
2606-
slots[slotName] = slots[slotName] || [];
2607-
slots[slotName].push(node);
2606+
slots[slotName] = slots[slotName] || window.document.createDocumentFragment();
2607+
slots[slotName].appendChild(node);
26082608
} else {
2609-
$template.push(node);
2609+
$template.appendChild(node);
26102610
}
26112611
});
26122612

@@ -2620,9 +2620,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
26202620
for (var slotName in slots) {
26212621
if (slots[slotName]) {
26222622
// Only define a transclusion function if the slot was filled
2623-
slots[slotName] = compilationGenerator(mightHaveMultipleTransclusionError, slots[slotName], transcludeFn);
2623+
slots[slotName] = compilationGenerator(mightHaveMultipleTransclusionError, slots[slotName].childNodes, transcludeFn);
26242624
}
26252625
}
2626+
2627+
$template = $template.childNodes;
26262628
}
26272629

26282630
$compileNode.empty(); // clear contents

test/ng/compileSpec.js

+44
Original file line numberDiff line numberDiff line change
@@ -8843,6 +8843,50 @@ describe('$compile', function() {
88438843
});
88448844
});
88458845

8846+
8847+
it('should correctly handle multi-element directives', function() {
8848+
module(function() {
8849+
directive('foo', valueFn({
8850+
template: '[<div ng-transclude></div>]',
8851+
transclude: true
8852+
}));
8853+
directive('bar', valueFn({
8854+
template: '[<div ng-transclude="header"></div>|<div ng-transclude="footer"></div>]',
8855+
transclude: {
8856+
header: 'header',
8857+
footer: 'footer'
8858+
}
8859+
}));
8860+
});
8861+
8862+
inject(function($compile, $rootScope) {
8863+
var tmplWithFoo =
8864+
'<foo>' +
8865+
'<div ng-if-start="true">Hello, </div>' +
8866+
'<div ng-if-end>world!</div>' +
8867+
'</foo>';
8868+
var tmplWithBar =
8869+
'<bar>' +
8870+
'<header ng-if-start="true">This is a </header>' +
8871+
'<header ng-if-end>header!</header>' +
8872+
'<footer ng-if-start="true">This is a </footer>' +
8873+
'<footer ng-if-end>footer!</footer>' +
8874+
'</bar>';
8875+
8876+
var elem1 = $compile(tmplWithFoo)($rootScope);
8877+
var elem2 = $compile(tmplWithBar)($rootScope);
8878+
8879+
$rootScope.$digest();
8880+
8881+
expect(elem1.text()).toBe('[Hello, world!]');
8882+
expect(elem2.text()).toBe('[This is a header!|This is a footer!]');
8883+
8884+
dealoc(elem1);
8885+
dealoc(elem2);
8886+
});
8887+
});
8888+
8889+
88468890
//see issue https://github.com/angular/angular.js/issues/12936
88478891
it('should use the proper scope when it is on the root element of a replaced directive template', function() {
88488892
module(function() {

0 commit comments

Comments
 (0)