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
This commit is contained in:
committed by
Martin Staffa
parent
b9f19ad0d4
commit
78b9f61366
+7
-5
@@ -2575,7 +2575,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
|
||||
// We have transclusion slots,
|
||||
// collect them up, compile them and store their transclusion functions
|
||||
$template = [];
|
||||
$template = window.document.createDocumentFragment();
|
||||
|
||||
var slotMap = createMap();
|
||||
var filledSlots = createMap();
|
||||
@@ -2603,10 +2603,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
var slotName = slotMap[directiveNormalize(nodeName_(node))];
|
||||
if (slotName) {
|
||||
filledSlots[slotName] = true;
|
||||
slots[slotName] = slots[slotName] || [];
|
||||
slots[slotName].push(node);
|
||||
slots[slotName] = slots[slotName] || window.document.createDocumentFragment();
|
||||
slots[slotName].appendChild(node);
|
||||
} else {
|
||||
$template.push(node);
|
||||
$template.appendChild(node);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -2620,9 +2620,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
for (var slotName in slots) {
|
||||
if (slots[slotName]) {
|
||||
// Only define a transclusion function if the slot was filled
|
||||
slots[slotName] = compilationGenerator(mightHaveMultipleTransclusionError, slots[slotName], transcludeFn);
|
||||
slots[slotName] = compilationGenerator(mightHaveMultipleTransclusionError, slots[slotName].childNodes, transcludeFn);
|
||||
}
|
||||
}
|
||||
|
||||
$template = $template.childNodes;
|
||||
}
|
||||
|
||||
$compileNode.empty(); // clear contents
|
||||
|
||||
@@ -8843,6 +8843,50 @@ describe('$compile', function() {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should correctly handle multi-element directives', function() {
|
||||
module(function() {
|
||||
directive('foo', valueFn({
|
||||
template: '[<div ng-transclude></div>]',
|
||||
transclude: true
|
||||
}));
|
||||
directive('bar', valueFn({
|
||||
template: '[<div ng-transclude="header"></div>|<div ng-transclude="footer"></div>]',
|
||||
transclude: {
|
||||
header: 'header',
|
||||
footer: 'footer'
|
||||
}
|
||||
}));
|
||||
});
|
||||
|
||||
inject(function($compile, $rootScope) {
|
||||
var tmplWithFoo =
|
||||
'<foo>' +
|
||||
'<div ng-if-start="true">Hello, </div>' +
|
||||
'<div ng-if-end>world!</div>' +
|
||||
'</foo>';
|
||||
var tmplWithBar =
|
||||
'<bar>' +
|
||||
'<header ng-if-start="true">This is a </header>' +
|
||||
'<header ng-if-end>header!</header>' +
|
||||
'<footer ng-if-start="true">This is a </footer>' +
|
||||
'<footer ng-if-end>footer!</footer>' +
|
||||
'</bar>';
|
||||
|
||||
var elem1 = $compile(tmplWithFoo)($rootScope);
|
||||
var elem2 = $compile(tmplWithBar)($rootScope);
|
||||
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(elem1.text()).toBe('[Hello, world!]');
|
||||
expect(elem2.text()).toBe('[This is a header!|This is a footer!]');
|
||||
|
||||
dealoc(elem1);
|
||||
dealoc(elem2);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
//see issue https://github.com/angular/angular.js/issues/12936
|
||||
it('should use the proper scope when it is on the root element of a replaced directive template', function() {
|
||||
module(function() {
|
||||
|
||||
Reference in New Issue
Block a user