fix(ivy): don't project removed placeholders with runtime i18n (#30783)
When translated content was projected, all of the content was reappended, even the placeholders that had been removed in the translation. To avoid that we added a new flag on `TNode` that specifies that a node is detached, in which case it should be ignored by the projection. FW-1319 #resolve PR Close #30783
This commit is contained in:
parent
05a43ca869
commit
30efb6b8ea
|
@ -19,7 +19,7 @@ import {attachI18nOpCodesDebug} from './instructions/lview_debug';
|
||||||
import {allocExpando, elementPropertyInternal, getOrCreateTNode, setInputsForProperty} from './instructions/shared';
|
import {allocExpando, elementPropertyInternal, getOrCreateTNode, setInputsForProperty} from './instructions/shared';
|
||||||
import {LContainer, NATIVE} from './interfaces/container';
|
import {LContainer, NATIVE} from './interfaces/container';
|
||||||
import {COMMENT_MARKER, ELEMENT_MARKER, I18nMutateOpCode, I18nMutateOpCodes, I18nUpdateOpCode, I18nUpdateOpCodes, IcuType, TI18n, TIcu} from './interfaces/i18n';
|
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 {RComment, RElement, RText} from './interfaces/renderer';
|
||||||
import {SanitizerFn} from './interfaces/sanitization';
|
import {SanitizerFn} from './interfaces/sanitization';
|
||||||
import {StylingContext} from './interfaces/styling';
|
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++;
|
ngDevMode && ngDevMode.rendererRemoveNode++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,19 +47,22 @@ export const enum TNodeType {
|
||||||
*/
|
*/
|
||||||
export const enum TNodeFlags {
|
export const enum TNodeFlags {
|
||||||
/** This bit is set if the node is a component */
|
/** This bit is set if the node is a component */
|
||||||
isComponent = 0b00001,
|
isComponent = 0b000001,
|
||||||
|
|
||||||
/** This bit is set if the node has been projected */
|
/** 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 */
|
/** 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 */
|
/** 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 */
|
/** 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,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -784,15 +784,17 @@ export function appendProjectedNodes(
|
||||||
appendChild(nodeToProject, tProjectionNode, lView);
|
appendChild(nodeToProject, tProjectionNode, lView);
|
||||||
} else {
|
} else {
|
||||||
while (nodeToProject) {
|
while (nodeToProject) {
|
||||||
if (nodeToProject.type === TNodeType.Projection) {
|
if (!(nodeToProject.flags & TNodeFlags.isDetached)) {
|
||||||
appendProjectedNodes(
|
if (nodeToProject.type === TNodeType.Projection) {
|
||||||
lView, tProjectionNode, (nodeToProject as TProjectionNode).projection,
|
appendProjectedNodes(
|
||||||
findComponentView(projectedView));
|
lView, tProjectionNode, (nodeToProject as TProjectionNode).projection,
|
||||||
} else {
|
findComponentView(projectedView));
|
||||||
// This flag must be set now or we won't know that this node is projected
|
} else {
|
||||||
// if the nodes are inserted into a container later.
|
// This flag must be set now or we won't know that this node is projected
|
||||||
nodeToProject.flags |= TNodeFlags.isProjected;
|
// if the nodes are inserted into a container later.
|
||||||
appendProjectedNode(nodeToProject, tProjectionNode, lView, projectedView);
|
nodeToProject.flags |= TNodeFlags.isProjected;
|
||||||
|
appendProjectedNode(nodeToProject, tProjectionNode, lView, projectedView);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
nodeToProject = nodeToProject.projectionNext;
|
nodeToProject = nodeToProject.projectionNext;
|
||||||
}
|
}
|
||||||
|
|
|
@ -939,8 +939,7 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
|
||||||
.toEqual('<child><grand-child><div><b>Bonjour</b> monde!</div></grand-child></child>');
|
.toEqual('<child><grand-child><div><b>Bonjour</b> monde!</div></grand-child></child>');
|
||||||
});
|
});
|
||||||
|
|
||||||
// FW-1319 Runtime i18n should be able to remove projected placeholders
|
it('should be able to remove projected placeholders', () => {
|
||||||
xit('should be able to remove projected placeholders', () => {
|
|
||||||
@Component({selector: 'grand-child', template: '<div><ng-content></ng-content></div>'})
|
@Component({selector: 'grand-child', template: '<div><ng-content></ng-content></div>'})
|
||||||
class GrandChild {
|
class GrandChild {
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue