New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(ivy): ViewRef.rootNodes
returns rootNodes from child views as well
#33457
Conversation
…ell. The idea behind `rootNodes` is to return all of the nodes which need to be added to the DOM in order for the `ViewRef` to be rendered. The new implementation correctly takes into account the case where one of the rootNodes is a container containing other `ViewRef`s.
if (tNodeChild.type === TNodeType.ElementContainer) { | ||
collectNativeNodes(lView, tNodeChild, result); | ||
} else if (tNodeChild.type === TNodeType.Projection) { | ||
if (tNode.type === TNodeType.ElementContainer) { |
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.
I don't see a test for the TNodeType.IcuContainer
in the series of node type checks. If I recall properly ICU containers "behave" similarly to <ng-container>
s. I'm not sure if we can bump into ICU containers here, but:
- if no, we should add an assert;
- if yes, we should add a test + handle this case.
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.
Also, I would add an assert to verify that we don't bump into tNode
being TNodeType.View
(just for completeness, to make sure that we are not missing handling of any TNode type).
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.
- I have added asserts
- Added tests and was not able to get
Icu
node to show up here.
selector: 'edit-form', | ||
template: ` | ||
<ng-template [dir]="true"> | ||
<div *ngIf="true">Text</div> |
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.
Could we add few more test cases:
- nested
<ng-container>
s at the root of an embedded view; - ICU inside
<ng-container>
- I'm not sure if we can have them at the root of a view; - a directive that asks for a
ViewContainerRef
at the root of a view (you've got a case where a VCRef is asked on a container);
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.
added test cases
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.
I haven't seen a test for the case where a ViewContainerRef
is injected on a regular element.
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.
Did the first pass. The direction LGTM but I'm not sure if we are handling all the cases of nodes that can be at the root of a view (left comments enumerating those cases). As the very minimum we need more tests.
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.
Updated, PTAL
if (tNodeChild.type === TNodeType.ElementContainer) { | ||
collectNativeNodes(lView, tNodeChild, result); | ||
} else if (tNodeChild.type === TNodeType.Projection) { | ||
if (tNode.type === TNodeType.ElementContainer) { |
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.
- I have added asserts
- Added tests and was not able to get
Icu
node to show up here.
selector: 'edit-form', | ||
template: ` | ||
<ng-template [dir]="true"> | ||
<div *ngIf="true">Text</div> |
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.
added test cases
} else if (tNode.type === TNodeType.Container) { | ||
const lContainer = lView[tNode.index]; | ||
const containerTView = tNode.tViews !as TView; | ||
ngDevMode && assertDefined(containerTView, 'TView expected'); |
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.
I don't think that this assert is correct for 2 reasons:
- it refers to a
TView
defined by this<ng-template>
and not inserted into aViewContainerRef
asked on this<ng-template>
; - many different types of TViews can be inserted into one container so we can't assume that all inserted views share the same
TView
- it can be
null
when the definition is empty<ng-template></ng-template>
, AFAIK
There is a confusion between an embedded view defintion and the the inserted instance here.
<ng-template [dir]="true"> | ||
<div *ngIf="true">Text</div> | ||
<ng-container>container-content</ng-container> | ||
<div i18n>assert TNodeType.IcuContainer is never a root node</div> |
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.
This is not enough, you need to have an actual ICU expression inside an element with the i18n
attribute. Also, having div
at the root is not enough as a <div>
is a root node so no need to descend any further. An example way of testing it would be <ng-container i18n>Updated {minutes, plural, =0 {just now} =1 {one minute ago} other {several minutes ago}}</ng-container>
and here we need to descent into the ICU container.
tl;dr; I still believe that we need to handle the case of a ICU container.
while (tNode) { | ||
ngDevMode && assertNodeOfPossibleTypes( | ||
tNode, TNodeType.Element, TNodeType.Container, TNodeType.Projection, | ||
TNodeType.ElementContainer); |
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.
I believe that we need to handle a ICU container, see: https://github.com/angular/angular/pull/33457/files#r340598750
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.
Closing in as @pkozlowski-opensource took over #33493 |
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
The idea behind
rootNodes
is to return all of the nodes which needto be added to the DOM in order for the
ViewRef
to be rendered.The new implementation correctly takes into account the case where
one of the rootNodes is a container containing other
ViewRef
s.