Skip to content
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(core): not inserting ViewContainerRef nodes when inside root of a component #39599

Closed
wants to merge 2 commits into from

Conversation

crisbeto
Copy link
Member

@crisbeto crisbeto commented Nov 7, 2020

When a ViewContainerRef is injected, we dynamically create a comment node next to the host so that it can be used as an anchor point for inserting views. The comment node is inserted through the appendChild helper from node_manipulation.ts in most cases.

The problem with using appendChild here is that it has some extra logic which doesn't return a parent RNode if an element is at the root of a component. I think that this is a performance optimization which is used to avoid inserting an element in one place in the DOM and then moving it a bit later when it is projected. This can break down in some cases when creating a ViewContainerRef for a non-component node at the root of another component like the following:

<root>
  <div #viewContainerRef></div>
</root>

In this case the #viewContainerRef node is at the root of a component so we intentionally don't insert it, but since its anchor element was created manually, it'll never be projected. This will prevent any views added through the ViewContainerRef from being inserted into the DOM.

These changes resolve the issue by not going through appendChild at all when creating a comment node for ViewContainerRef. This should work identically since appendChild doesn't really do anything with the T structures anyway, it only uses them to reach the relevant DOM nodes.

Fixes #39556.

@google-cla google-cla bot added the cla: yes label Nov 7, 2020
@crisbeto crisbeto force-pushed the 39556/vcr-root-insert branch from fbffcd5 to 60273a3 Compare Nov 7, 2020
@ngbot ngbot bot added this to the needsTriage milestone Nov 7, 2020
@ngbot ngbot bot added this to the needsTriage milestone Nov 7, 2020
@ngbot ngbot bot added this to the needsTriage milestone Nov 7, 2020
@crisbeto crisbeto marked this pull request as ready for review Nov 7, 2020
@pullapprove pullapprove bot requested a review from AndrewKushnir Nov 7, 2020
const tNode = tData[parentTNode.index] as TNode;
const encapsulation = (tData[tNode.directiveStart] as ComponentDef<any>).encapsulation;
const encapsulation =
(tView.data[parentTNode.directiveStart] as ComponentDef<unknown>).encapsulation;
Copy link
Member Author

@crisbeto crisbeto Nov 7, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These changes aren't required for the fix, I just noticed that the tNode and parentTNode are always the same here.

@AndrewKushnir AndrewKushnir requested a review from mhevery Nov 9, 2020
Copy link
Contributor

@AndrewKushnir AndrewKushnir left a comment

The change LGTM, thanks @crisbeto 👍

I've also added @mhevery as a reviewer, I think his input might also be very helpful.

Copy link
Contributor

@mhevery mhevery left a comment

LGTM, but please take care of @AndrewKushnir 's comments

crisbeto added 2 commits Nov 10, 2020
… component

When a `ViewContainerRef` is injected, we dynamically create a comment node next to the host
so that it can be used as an anchor point for inserting views. The comment node is inserted
through the `appendChild` helper from `node_manipulation.ts` in most cases.

The problem with using `appendChild` here is that it has some extra logic which doesn't return
a parent `RNode` if an element is at the root of a component. I __think__ that this is a performance
optimization which is used to avoid inserting an element in one place in the DOM and then
moving it a bit later when it is projected. This can break down in some cases when creating
a `ViewContainerRef` for a non-component node at the root of another component like the following:

```
<root>
  <div #viewContainerRef></div>
</root>
```

In this case the `#viewContainerRef` node is at the root of a component so we intentionally don't
insert it, but since its anchor element was created manually, it'll never be projected. This will
prevent any views added through the `ViewContainerRef` from being inserted into the DOM.

These changes resolve the issue by not going through `appendChild` at all when creating a comment
node for `ViewContainerRef`. This should work identically since `appendChild` doesn't really do
anything with the T structures anyway, it only uses them to reach the relevant DOM nodes.

Fixes angular#39556.
@crisbeto
Copy link
Member Author

@crisbeto crisbeto commented Nov 10, 2020

@AndrewKushnir the feedback has been addressed.

@AndrewKushnir
Copy link
Contributor

@AndrewKushnir AndrewKushnir commented Nov 10, 2020

@AndrewKushnir
Copy link
Contributor

@AndrewKushnir AndrewKushnir commented Nov 11, 2020

@crisbeto FYI presubmit is successful for the changes in this PR. The missing piece is the "target" label, could you please set one when you get a chance? Thank you.

atscott added a commit that referenced this issue Nov 12, 2020
… component (#39599)

When a `ViewContainerRef` is injected, we dynamically create a comment node next to the host
so that it can be used as an anchor point for inserting views. The comment node is inserted
through the `appendChild` helper from `node_manipulation.ts` in most cases.

The problem with using `appendChild` here is that it has some extra logic which doesn't return
a parent `RNode` if an element is at the root of a component. I __think__ that this is a performance
optimization which is used to avoid inserting an element in one place in the DOM and then
moving it a bit later when it is projected. This can break down in some cases when creating
a `ViewContainerRef` for a non-component node at the root of another component like the following:

```
<root>
  <div #viewContainerRef></div>
</root>
```

In this case the `#viewContainerRef` node is at the root of a component so we intentionally don't
insert it, but since its anchor element was created manually, it'll never be projected. This will
prevent any views added through the `ViewContainerRef` from being inserted into the DOM.

These changes resolve the issue by not going through `appendChild` at all when creating a comment
node for `ViewContainerRef`. This should work identically since `appendChild` doesn't really do
anything with the T structures anyway, it only uses them to reach the relevant DOM nodes.

Fixes #39556.

PR Close #39599
basherr added a commit to basherr/angular that referenced this issue Nov 14, 2020
… component (angular#39599)

When a `ViewContainerRef` is injected, we dynamically create a comment node next to the host
so that it can be used as an anchor point for inserting views. The comment node is inserted
through the `appendChild` helper from `node_manipulation.ts` in most cases.

The problem with using `appendChild` here is that it has some extra logic which doesn't return
a parent `RNode` if an element is at the root of a component. I __think__ that this is a performance
optimization which is used to avoid inserting an element in one place in the DOM and then
moving it a bit later when it is projected. This can break down in some cases when creating
a `ViewContainerRef` for a non-component node at the root of another component like the following:

```
<root>
  <div #viewContainerRef></div>
</root>
```

In this case the `#viewContainerRef` node is at the root of a component so we intentionally don't
insert it, but since its anchor element was created manually, it'll never be projected. This will
prevent any views added through the `ViewContainerRef` from being inserted into the DOM.

These changes resolve the issue by not going through `appendChild` at all when creating a comment
node for `ViewContainerRef`. This should work identically since `appendChild` doesn't really do
anything with the T structures anyway, it only uses them to reach the relevant DOM nodes.

Fixes angular#39556.

PR Close angular#39599
@angular-automatic-lock-bot
Copy link

@angular-automatic-lock-bot angular-automatic-lock-bot bot commented Dec 13, 2020

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Dec 13, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

4 participants