fix(ivy): handle ICU expressions in executeActionOnNode
(#31313)
When `walkTNodeTree` was refactored, the case of ICU expressions was forgotten (because it was handled in the `else` previously). This PR fixes that to handle it like `ElementContainer`. FW-1411 #resolve PR Close #31313
This commit is contained in:
parent
119004c7d4
commit
4f38419e33
@ -14,7 +14,7 @@ import {attachPatchData} from './context_discovery';
|
|||||||
import {CONTAINER_HEADER_OFFSET, LContainer, NATIVE, unusedValueExportToPlacateAjd as unused1} from './interfaces/container';
|
import {CONTAINER_HEADER_OFFSET, LContainer, NATIVE, unusedValueExportToPlacateAjd as unused1} from './interfaces/container';
|
||||||
import {ComponentDef} from './interfaces/definition';
|
import {ComponentDef} from './interfaces/definition';
|
||||||
import {NodeInjectorFactory} from './interfaces/injector';
|
import {NodeInjectorFactory} from './interfaces/injector';
|
||||||
import {TElementContainerNode, TElementNode, TNode, TNodeFlags, TNodeType, TProjectionNode, TViewNode, unusedValueExportToPlacateAjd as unused2} from './interfaces/node';
|
import {TElementContainerNode, TElementNode, TIcuContainerNode, TNode, TNodeFlags, TNodeType, TProjectionNode, TViewNode, unusedValueExportToPlacateAjd as unused2} from './interfaces/node';
|
||||||
import {unusedValueExportToPlacateAjd as unused3} from './interfaces/projection';
|
import {unusedValueExportToPlacateAjd as unused3} from './interfaces/projection';
|
||||||
import {ProceduralRenderer3, RElement, RNode, RText, Renderer3, isProceduralRenderer, unusedValueExportToPlacateAjd as unused4} from './interfaces/renderer';
|
import {ProceduralRenderer3, RElement, RNode, RText, Renderer3, isProceduralRenderer, unusedValueExportToPlacateAjd as unused4} from './interfaces/renderer';
|
||||||
import {StylingContext} from './interfaces/styling';
|
import {StylingContext} from './interfaces/styling';
|
||||||
@ -844,23 +844,23 @@ function executeActionOnContainer(
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* `executeActionOnElementContainer` performs an operation on the ng-container node and its child
|
* `executeActionOnElementContainerOrIcuContainer` performs an operation on the ng-container node
|
||||||
* nodes as specified by the `action` (insert, detach, destroy).
|
* and its child nodes as specified by the `action` (insert, detach, destroy).
|
||||||
*
|
*
|
||||||
* @param renderer Renderer to use
|
* @param renderer Renderer to use
|
||||||
* @param action action to perform (insert, detach, destroy)
|
* @param action action to perform (insert, detach, destroy)
|
||||||
* @param lView The LView which needs to be inserted, detached, destroyed.
|
* @param lView The LView which needs to be inserted, detached, destroyed.
|
||||||
* @param tElementContainerNode The TNode associated with the ElementContainer.
|
* @param tNode The TNode associated with the `ElementContainer` or `IcuContainer`.
|
||||||
* @param renderParent parent DOM element for insertion/removal.
|
* @param renderParent parent DOM element for insertion/removal.
|
||||||
* @param beforeNode Before which node the insertions should happen.
|
* @param beforeNode Before which node the insertions should happen.
|
||||||
*/
|
*/
|
||||||
function executeActionOnElementContainer(
|
function executeActionOnElementContainerOrIcuContainer(
|
||||||
renderer: Renderer3, action: WalkTNodeTreeAction, lView: LView,
|
renderer: Renderer3, action: WalkTNodeTreeAction, lView: LView,
|
||||||
tElementContainerNode: TElementContainerNode, renderParent: RElement | null,
|
tNode: TElementContainerNode | TIcuContainerNode, renderParent: RElement | null,
|
||||||
beforeNode: RNode | null | undefined) {
|
beforeNode: RNode | null | undefined) {
|
||||||
const node = lView[tElementContainerNode.index];
|
const node = lView[tNode.index];
|
||||||
executeActionOnElementOrContainer(action, renderer, renderParent, node, beforeNode);
|
executeActionOnElementOrContainer(action, renderer, renderParent, node, beforeNode);
|
||||||
let childTNode: TNode|null = tElementContainerNode.child;
|
let childTNode: TNode|null = tNode.child;
|
||||||
while (childTNode) {
|
while (childTNode) {
|
||||||
executeActionOnNode(renderer, action, lView, childTNode, renderParent, beforeNode);
|
executeActionOnNode(renderer, action, lView, childTNode, renderParent, beforeNode);
|
||||||
childTNode = childTNode.next;
|
childTNode = childTNode.next;
|
||||||
@ -871,9 +871,11 @@ function executeActionOnNode(
|
|||||||
renderer: Renderer3, action: WalkTNodeTreeAction, lView: LView, tNode: TNode,
|
renderer: Renderer3, action: WalkTNodeTreeAction, lView: LView, tNode: TNode,
|
||||||
renderParent: RElement | null, beforeNode: RNode | null | undefined): void {
|
renderParent: RElement | null, beforeNode: RNode | null | undefined): void {
|
||||||
const elementContainerRootTNodeType = tNode.type;
|
const elementContainerRootTNodeType = tNode.type;
|
||||||
if (elementContainerRootTNodeType === TNodeType.ElementContainer) {
|
if (elementContainerRootTNodeType === TNodeType.ElementContainer ||
|
||||||
executeActionOnElementContainer(
|
elementContainerRootTNodeType === TNodeType.IcuContainer) {
|
||||||
renderer, action, lView, tNode as TElementContainerNode, renderParent, beforeNode);
|
executeActionOnElementContainerOrIcuContainer(
|
||||||
|
renderer, action, lView, tNode as TElementContainerNode | TIcuContainerNode, renderParent,
|
||||||
|
beforeNode);
|
||||||
} else if (elementContainerRootTNodeType === TNodeType.Projection) {
|
} else if (elementContainerRootTNodeType === TNodeType.Projection) {
|
||||||
executeActionOnProjection(
|
executeActionOnProjection(
|
||||||
renderer, action, lView, tNode as TProjectionNode, renderParent, beforeNode);
|
renderer, action, lView, tNode as TProjectionNode, renderParent, beforeNode);
|
||||||
|
@ -772,6 +772,40 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
|
|||||||
expect(fixture.debugElement.nativeElement.innerHTML)
|
expect(fixture.debugElement.nativeElement.innerHTML)
|
||||||
.toBe('<my-cmp><div>ONE<!--ICU 15--></div><!--container--></my-cmp>');
|
.toBe('<my-cmp><div>ONE<!--ICU 15--></div><!--container--></my-cmp>');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('with nested containers', () => {
|
||||||
|
@Component({
|
||||||
|
selector: 'comp',
|
||||||
|
template: `
|
||||||
|
<ng-container [ngSwitch]="visible">
|
||||||
|
<ng-container *ngSwitchCase="isVisible()" i18n>
|
||||||
|
{type, select, A { A } B { B } other { C }}
|
||||||
|
</ng-container>
|
||||||
|
<ng-container *ngSwitchCase="!isVisible()" i18n>
|
||||||
|
{type, select, A1 { A1 } B1 { B1 } other { C1 }}
|
||||||
|
</ng-container>
|
||||||
|
</ng-container>
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
class Comp {
|
||||||
|
type = 'A';
|
||||||
|
visible = true;
|
||||||
|
isVisible() { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
TestBed.configureTestingModule({declarations: [Comp]});
|
||||||
|
|
||||||
|
const fixture = TestBed.createComponent(Comp);
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
expect(fixture.debugElement.nativeElement.innerHTML).toContain('A');
|
||||||
|
|
||||||
|
fixture.componentInstance.visible = false;
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
expect(fixture.debugElement.nativeElement.innerHTML).not.toContain('A');
|
||||||
|
expect(fixture.debugElement.nativeElement.innerHTML).toContain('C1');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('should support attributes', () => {
|
describe('should support attributes', () => {
|
||||||
|
@ -675,10 +675,10 @@
|
|||||||
"name": "executeActionOnContainer"
|
"name": "executeActionOnContainer"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "executeActionOnElementContainer"
|
"name": "executeActionOnElementOrContainer"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "executeActionOnElementOrContainer"
|
"name": "executeActionOnElementContainerOrIcuContainer"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "executeActionOnNode"
|
"name": "executeActionOnNode"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user