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

Commit 9918b74

Browse files
committed
fix(compiler): allow transclusion of root elements
Fixed an issue where a directive that uses transclusion (such as ngRepeat) failed to link if it was declared on the root element of the compilation tree. (For example ngView or ngInclude including template where ngRepeat was the top most element).
1 parent 6ecac8e commit 9918b74

File tree

7 files changed

+41
-15
lines changed

7 files changed

+41
-15
lines changed

src/Angular.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -936,7 +936,7 @@ function bindJQuery() {
936936
JQLitePatchJQueryRemove('empty');
937937
JQLitePatchJQueryRemove('html');
938938
} else {
939-
jqLite = jqLiteWrap;
939+
jqLite = JQLite;
940940
}
941941
angular.element = jqLite;
942942
}

src/angular.suffix

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
publishExternalAPI(angular);
66

7-
jqLiteWrap(document).ready(function() {
7+
JQLite(document).ready(function() {
88
angularInit(document, bootstrap);
99
});
1010

src/jqLite.js

+10-9
Original file line numberDiff line numberDiff line change
@@ -168,17 +168,18 @@ function JQLitePatchJQueryRemove(name, dispatchThis) {
168168
}
169169

170170
/////////////////////////////////////////////
171-
function jqLiteWrap(element) {
172-
if (isString(element) && element.charAt(0) != '<') {
173-
throw new Error('selectors not implemented');
174-
}
175-
return new JQLite(element);
176-
}
177-
178171
function JQLite(element) {
179172
if (element instanceof JQLite) {
180173
return element;
181-
} else if (isString(element)) {
174+
}
175+
if (!(this instanceof JQLite)) {
176+
if (isString(element) && element.charAt(0) != '<') {
177+
throw Error('selectors not implemented');
178+
}
179+
return new JQLite(element);
180+
}
181+
182+
if (isString(element)) {
182183
var div = document.createElement('div');
183184
// Read about the NoScope elements here:
184185
// http://msdn.microsoft.com/en-us/library/ms533897(VS.85).aspx
@@ -299,7 +300,7 @@ var JQLitePrototype = JQLite.prototype = {
299300

300301
this.bind('DOMContentLoaded', trigger); // works for modern browsers and IE9
301302
// we can not use jqLite since we are not done loading and jQuery could be loaded later.
302-
jqLiteWrap(window).bind('load', trigger); // fallback to window.onload for others
303+
JQLite(window).bind('load', trigger); // fallback to window.onload for others
303304
},
304305
toString: function() {
305306
var value = [];

src/scenario/angular.suffix

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ angular.forEach(script.attributes, function(attr) {
1414
});
1515

1616
if (config.autotest) {
17-
jqLiteWrap(document).ready(function() {
17+
JQLite(document).ready(function() {
1818
angular.scenario.setUpAndRun(config);
1919
});
2020
}

src/service/compiler.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,10 @@ function $CompileProvider($provide) {
225225
//================================
226226

227227
function compile(templateElement, transcludeFn, maxPriority) {
228-
templateElement = jqLite(templateElement);
228+
if (!(templateElement instanceof jqLite)) {
229+
// jquery always rewraps, where as we need to preserve the original selector so that we can modify it.
230+
templateElement = jqLite(templateElement);
231+
}
229232
// We can not compile top level text elements since text nodes can be merged and we will
230233
// not be able to attach scope data to them, so we will wrap them in <span>
231234
forEach(templateElement, function(node, index){
@@ -488,7 +491,7 @@ function $CompileProvider($provide) {
488491
template = jqLite(templateNode);
489492
templateNode = (element = templateAttrs.$element = jqLite(
490493
'<!-- ' + directiveName + ': ' + templateAttrs[directiveName] + ' -->'))[0];
491-
template.replaceWith(templateNode);
494+
replaceWith(rootElement, jqLite(template[0]), templateNode);
492495
childTranscludeFn = compile(template, transcludeFn, terminalPriority);
493496
} else {
494497
template = jqLite(JQLiteClone(templateNode));

test/jqLiteSpec.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ describe('jqLite', function() {
3939

4040

4141
it('should be jqLite when jqLiteMode is on, otherwise jQuery', function() {
42-
expect(jqLite).toBe(_jqLiteMode ? jqLiteWrap : _jQuery);
42+
expect(jqLite).toBe(_jqLiteMode ? JQLite : _jQuery);
4343
});
4444

4545

test/service/compilerSpec.js

+22
Original file line numberDiff line numberDiff line change
@@ -1751,5 +1751,27 @@ describe('$compile', function() {
17511751
});
17521752
});
17531753

1754+
1755+
it('should support transcluded element on root content', function() {
1756+
var comment;
1757+
module(function($compileProvider) {
1758+
$compileProvider.directive('transclude', valueFn({
1759+
transclude: 'element',
1760+
compile: function(element, attr, linker) {
1761+
return function(scope, element, attr) {
1762+
comment = element;
1763+
};
1764+
}
1765+
}));
1766+
});
1767+
inject(function($compile, $rootScope) {
1768+
var element = jqLite('<div>before<div transclude></div>after</div>').contents();
1769+
expect(element.length).toEqual(3);
1770+
expect(nodeName_(element[1])).toBe('DIV');
1771+
$compile(element)($rootScope);
1772+
expect(nodeName_(element[1])).toBe('#comment');
1773+
expect(nodeName_(comment)).toBe('#comment');
1774+
});
1775+
});
17541776
});
17551777
});

0 commit comments

Comments
 (0)