-
Notifications
You must be signed in to change notification settings - Fork 27.4k
fix($compile): Detect when a directive compile
removes tElement
#9202
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1067,10 +1067,21 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { | |
function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective, | ||
previousCompileContext) { | ||
var linkFns = [], | ||
attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound, nodeLinkFnFound; | ||
attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound, nodeLinkFnFound, | ||
i, canary = '' + Math.random(); | ||
|
||
// While doing the main loop, there is the possibility that the element that we just compiled | ||
// is removed from `nodeList` and not just replaced with a comment or another element. | ||
// To detect this, we put a canary on all elements and remove it once the element is processed | ||
// https://github.com/angular/angular.js/issues/9198 | ||
for (i = 0; i < nodeList.length; ++i) { | ||
nodeList[i].ngCanary = canary; | ||
} | ||
|
||
for (var i = 0; i < nodeList.length; i++) { | ||
i = 0; | ||
while (i < nodeList.length) { | ||
attrs = new Attributes(); | ||
nodeList[i].ngCanary = undefined; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is better --- We could still shrink this a bit, though, by adding This would let us remove the initial loop. It doesn't make a huge difference though There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If nodeList[i] has a directive with -begin, then just marking the next node would not make it |
||
|
||
// we must always refer to nodeList[i] since the nodes can be replaced underneath us. | ||
directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined, | ||
|
@@ -1102,6 +1113,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { | |
|
||
//use the previous context only for the first element in the virtual group | ||
previousCompileContext = null; | ||
|
||
// nodeList is a *live* list of elements, so there is a chance that the node we just compile | ||
// was removed from nodeList (not just replaced with something else), and the node at | ||
// nodeList[i] is a node that was not processed | ||
if (nodeList[i].ngCanary != canary) i++; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't like this change because it makes the code much harder to follow and by monkey-patching DOM node object, we are increasing memory consumption (v8 doesn't like when these objects get monkey-patched). could we just check if the element at the current index changed after we applied directives to the current node? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just checking if the element changed would make the code even harder to understand as there are many cases we have to handle 1/ The element is the same (simple) It is possible to do all this without adding a canary, but the code will be slightly more complex |
||
} | ||
|
||
// return a linking function if we have found anything, null otherwise | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you remove it before the element is processed and after the element is processed you check if the current node doesn't have canary flag any more. no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes