You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix($compile): correctly merge consecutive text nodes on IE11
As explained in angular#11781 and angular#14924, IE11 can (under certain circumstances) break up a text node into
multiple consecutive ones, breaking interpolated expressions (e.g. `{{'foo'}}` would become
`{{` + `'foo'}}`). To work-around this IE11 bug, angular#11796 introduced extra logic to merge consecutive
text nodes (on IE11 only), which relies on the text nodes' having the same `parentNode`.
This approach works fine in the common case, where `compileNodes` is called with a live NodeList
object, because removing a text node from its parent will automatically update the latter's
`.childNodes` NodeList. It falls short though, when calling `compileNodes` with either a
jqLite/jQuery collection or an Array. In fails in two ways:
1. If the text nodes do not have a parent at the moment of compiling, there will be no merging.
(This happens for example on directives with `$transclude: {...}`.)
2. If the text nodes do have a parent, just removing a text node from its parent does **not** remove
it from the collection/array, which means that the merged text nodes will still get compiled and
linked (and possibly be displayed in the view). E.g. `['{{text1}}', '{{text2}}', '{{text3}}']`
will become `['{{text1}}{{text2}}{{text3}}', '{{text2}}', '{{text3}}']`.
--
This commit works around the above problems by:
1. Merging consecutive text nodes in the provided list, even if they have no parent.
2. When merging a txt node, explicitly remove it from the list (unless it is a live, auto-updating
list).
This can nonetheless have undesirable (albeit rare) side effects by overzealously merging text
nodes that are not meant to be merged (see "BREAKING CHANGE" section below).
Fixesangular#14924
BREAKING CHANGE:
**Note:** Everything described below affects **IE11 only**.
Previously, consecutive text nodes would not get merged if they had no parent. They will now, which
might have unexpectd side effects in the following cases:
1. Passing an array or jqLite/jQuery collection of parent-less text nodes to `$compile` directly:
```js
// Assuming:
var textNodes = [
document.createTextNode('{{'),
document.createTextNode('"foo"'),
document.createTextNode('}}')
];
var compiledNodes = $compile(textNodes)($rootScope);
// Before:
console.log(compiledNodes.length); // 3
console.log(compiledNodes.text()); // {{'foo'}}
// After:
console.log(compiledNodes.length); // 1
console.log(compiledNodes.text()); // foo
// To get the old behavior, compile each node separately:
var textNodes = [
document.createTextNode('{{'),
document.createTextNode('"foo"'),
document.createTextNode('}}')
];
var compiledNodes = angular.element(textNodes.map(function (node) {
return $compile(node)($rootScope)[0];
}));
```
2. Using multi-slot transclusion with non-consecutive, default-content text nodes (that form
interpolated expressions when merged):
```js
// Assuming the following component:
.compoent('someThing', {
template: '<ng-transclude><!-- Default content goes here --></ng-transclude>'
transclude: {
ignored: 'veryImportantContent'
}
})
```
```html
<!-- And assuming the following view: -->
<some-thing>
{{
<very-important-content>Nooot</very-important-content>
'foo'}}
</some-thing>
<!-- Before: -->
<some-thing>
<ng-transclude>
{{ <-- Two separate
'foo'}} <-- text nodes
</ng-transclude>
</some-thing>
<!-- After: -->
<some-thing>
<ng-transclude>
foo <-- The text nodes were merged into `{{'foo'}}`, which was then interpolated
</ng-transclude>
</some-thing>
<!-- To (visually) get the old behavior, wrap top-level text-nodes on -->
<!-- multi-slot transclusion directives into `<span>`; e.g.: -->
<some-thing>
<span>{{</span>
<very-important-content>Nooot</very-important-content>
<span>'foo'}}</span>
</some-thing>
<!-- Result: -->
<some-thing>
<ng-transclude>
<span>{{</span> <-- Two separate
<span>'foo'}}</span> <-- nodes
</ng-transclude>
</some-thing>
```
0 commit comments