diff --git a/packages/core/src/render3/i18n.ts b/packages/core/src/render3/i18n.ts index bdf88e081e..20729712a2 100644 --- a/packages/core/src/render3/i18n.ts +++ b/packages/core/src/render3/i18n.ts @@ -19,7 +19,7 @@ import {attachI18nOpCodesDebug} from './instructions/lview_debug'; import {allocExpando, elementPropertyInternal, getOrCreateTNode, setInputsForProperty} from './instructions/shared'; import {LContainer, NATIVE} from './interfaces/container'; import {COMMENT_MARKER, ELEMENT_MARKER, I18nMutateOpCode, I18nMutateOpCodes, I18nUpdateOpCode, I18nUpdateOpCodes, IcuType, TI18n, TIcu} from './interfaces/i18n'; -import {TElementNode, TIcuContainerNode, TNode, TNodeType, TProjectionNode} from './interfaces/node'; +import {TElementNode, TIcuContainerNode, TNode, TNodeFlags, TNodeType, TProjectionNode} from './interfaces/node'; import {RComment, RElement, RText} from './interfaces/renderer'; import {SanitizerFn} from './interfaces/sanitization'; import {StylingContext} from './interfaces/styling'; @@ -910,6 +910,8 @@ function removeNode(index: number, viewData: LView) { } } + // Define this node as detached so that we don't risk projecting it + removedPhTNode.flags |= TNodeFlags.isDetached; ngDevMode && ngDevMode.rendererRemoveNode++; } diff --git a/packages/core/src/render3/interfaces/node.ts b/packages/core/src/render3/interfaces/node.ts index 4e88949712..3ecb11f346 100644 --- a/packages/core/src/render3/interfaces/node.ts +++ b/packages/core/src/render3/interfaces/node.ts @@ -47,19 +47,22 @@ export const enum TNodeType { */ export const enum TNodeFlags { /** This bit is set if the node is a component */ - isComponent = 0b00001, + isComponent = 0b000001, /** This bit is set if the node has been projected */ - isProjected = 0b00010, + isProjected = 0b000010, /** This bit is set if any directive on this node has content queries */ - hasContentQuery = 0b00100, + hasContentQuery = 0b000100, /** This bit is set if the node has any "class" inputs */ - hasClassInput = 0b01000, + hasClassInput = 0b001000, /** This bit is set if the node has any "style" inputs */ - hasStyleInput = 0b10000, + hasStyleInput = 0b010000, + + /** This bit is set if the node has been detached by i18n */ + isDetached = 0b100000, } /** diff --git a/packages/core/src/render3/node_manipulation.ts b/packages/core/src/render3/node_manipulation.ts index 8fc447f32b..50dd8cd1d9 100644 --- a/packages/core/src/render3/node_manipulation.ts +++ b/packages/core/src/render3/node_manipulation.ts @@ -784,15 +784,17 @@ export function appendProjectedNodes( appendChild(nodeToProject, tProjectionNode, lView); } else { while (nodeToProject) { - if (nodeToProject.type === TNodeType.Projection) { - appendProjectedNodes( - lView, tProjectionNode, (nodeToProject as TProjectionNode).projection, - findComponentView(projectedView)); - } else { - // This flag must be set now or we won't know that this node is projected - // if the nodes are inserted into a container later. - nodeToProject.flags |= TNodeFlags.isProjected; - appendProjectedNode(nodeToProject, tProjectionNode, lView, projectedView); + if (!(nodeToProject.flags & TNodeFlags.isDetached)) { + if (nodeToProject.type === TNodeType.Projection) { + appendProjectedNodes( + lView, tProjectionNode, (nodeToProject as TProjectionNode).projection, + findComponentView(projectedView)); + } else { + // This flag must be set now or we won't know that this node is projected + // if the nodes are inserted into a container later. + nodeToProject.flags |= TNodeFlags.isProjected; + appendProjectedNode(nodeToProject, tProjectionNode, lView, projectedView); + } } nodeToProject = nodeToProject.projectionNext; } diff --git a/packages/core/test/acceptance/i18n_spec.ts b/packages/core/test/acceptance/i18n_spec.ts index 16c37d6a39..81e56ac043 100644 --- a/packages/core/test/acceptance/i18n_spec.ts +++ b/packages/core/test/acceptance/i18n_spec.ts @@ -939,8 +939,7 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { .toEqual('
Bonjour monde!
'); }); - // FW-1319 Runtime i18n should be able to remove projected placeholders - xit('should be able to remove projected placeholders', () => { + it('should be able to remove projected placeholders', () => { @Component({selector: 'grand-child', template: '
'}) class GrandChild { }