Repository: angular
Issue: Projected content is not hidden when dynamically creating a component if there is nowhere to project the content yet
Labels: area: core,core: content projection,core: dynamic view creation

### Which @angular/* package(s) are the source of the bug?

core

### Is this a regression?

No

### Description

When creating a component dynamically via `ViewContainerRef.createComponent()`, any content children created via `ViewContainerRef.createEmbeddedView()` and provided through `options.projectableContent` are not detached from the document if the dynamically created component does not have a location to project content to yet. Instead, they remain attached to the document outside of the component they were supposed to be projected into. If this is not the intended way to do this, please correct me, but this was the only way I found to data bind the embedded view to the component its template was declared in.


```ts
function render<C>(
  componentType: Type<C>,
  viewContainerRef: ViewContainerRef,
  templateRef: TemplateRef<any>
): void {
  const embeddedViewRef = viewContainerRef.createEmbeddedView(templateRef);
  viewContainerRef.createComponent(componentType, {
    projectableNodes: [embeddedViewRef.rootNodes],
  });
}
```

This situation arises with components that don't project content, or conditionally project content. For components with conditionally projected content specifically, once there is a location to project the content, the content will be moved there. If that location becomes unavailable again later, the projected content is properly detached from the document.

![image](https://github.com/angular/angular/assets/111467777/4d3812df-4a93-4fd8-8f9c-8c3a938157ac)

I expect projecting content in dynamically created components to be consistent with projecting content declaratively, which will always detach the content to project from the document if there is nowhere to project it. If this inconsistency is intentional, then I expect there to be a documented solution for replicating the behavior of projecting content declaratively when dynamically creating a component.

### Please provide a link to a minimal reproduction of the bug

https://stackblitz.com/edit/projected-content-not-hidden-dynamic-components?file=src%2Fapp%2Fapp.component.html

### Please provide the exception or error you saw

N/A. No errors in console.

### Please provide the environment you discovered this bug in (run `ng version`)

```true
Angular CLI: 16.2.12
Node: 16.20.2
Package Manager: npm 9.8.1
OS: win32 x64

Angular: 16.2.12
... animations, cli, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, router

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1602.12
@angular-devkit/build-angular   16.2.0
@angular-devkit/core            16.2.12
@angular-devkit/schematics      16.2.12
@angular/cdk                    16.2.14
@angular/material               16.2.14
@schematics/angular             16.2.12
rxjs                            7.8.1
typescript                      5.1.6
zone.js                         0.13.3
```


### Anything else?

There is a single workaround for both the no projectable content and conditionally projectable content cases, which is to use `Renderer2` to manually detach the elements created in the embedded view from the document before providing them to the component. I have provided examples of this workaround in the linked StackBlitz.

```ts
function renderWorkaround<C>(
  componentType: Type<C>,
  viewContainerRef: ViewContainerRef,
  templateRef: TemplateRef<any>,
  renderer: Renderer2
): void {
  const embeddedViewRef = viewContainerRef.createEmbeddedView(templateRef);
  for (const node of embeddedViewRef.rootNodes) {
    renderer.removeChild(node.parentNode, node);
  }
  viewContainerRef.createComponent(componentType, {
    projectableNodes: [embeddedViewRef.rootNodes],
  });
}
```

![image](https://github.com/angular/angular/assets/111467777/323b9a4c-8225-4285-9a28-6d46052b44b9)

I am aware that this issue could theoretically be solved by [using the suggested alternative to `<ng-content>` for conditional content projection](https://angular.io/guide/content-projection#conditional-content-projection), but my attempted solution of passing `TemplateRef.element.nativeElement` (which is just a comment) in `options.projectableNodes` when creating the component that projects content would not let me retrieve the `TemplateRef` via `@ContentChild` later.

I discovered this issue while implementing the [longstanding workaround](https://github.com/angular/components/issues/13784#issuecomment-440137435) for [cdkDragHandle being ignored when it is placed inside a child component](https://github.com/angular/components/issues/13784) for my dynamically created components. I figure it is worth mentioning as that issue was closed without an official solution over 5 years ago on the basis that it was not possible at the time. It might be worth revisiting if it is possible now.