angular: Cannot create component without inserting into DOM without the deprecated `ComponentFactory`

Which @angular/* package(s) are the source of the bug?

core

Is this a regression?

No

Description

Since Angular 13 ComponentFactory.create() is deprecated. It is advertised that we should instead use ViewContainerRef.createComponent(). However the behavior between those two methods are different and cannot necessarily replace each other for all use-cases.

My use-case is to create a component dynamically, not insert it into DOM, call a few custom methods on it, and then destroy the component. But ViewContainerRef.createComponent() will always insert the newly created component into DOM, wreaking havoc in my layout.

Basically I’d like to do something like that:

private validate(component: Type<DropdownComponent>): boolean {
    const injector = Injector.create({providers: this.getMyCustomProvider(), parent: this.getMyParentInjector()});
    const factory = this.componentFactoryResolver.resolveComponentFactory<DropdownComponent>(component);

    const dropdownComponentRef = factory.create(injector);
    const result = dropdownComponentRef.instance.isValid();
    dropdownComponentRef.destroy();

    return result;
}

Was it intentional that a component cannot be instantiated without being inserted into DOM anymore ? Or should it be considered a regression in the feature set of the framework ?

Or is there an alternative API that would allow me to instantiate and destroy components without ever inserting them into DOM ?

Please provide a link to a minimal reproduction of the bug

No response

Please provide the exception or error you saw

No response

Please provide the environment you discovered this bug in (run ng version)

Angular CLI: 13.2.5
Node: 14.19.0
Package Manager: yarn 1.22.17
OS: linux x64

Angular: 13.2.5
... animations, cdk, cli, common, compiler, compiler-cli, core
... forms, language-service, localize, material
... platform-browser, platform-browser-dynamic, router

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1302.5
@angular-devkit/build-angular   13.2.5
@angular-devkit/core            13.2.5
@angular-devkit/schematics      13.2.5
@angular/flex-layout            13.0.0-beta.38
@schematics/angular             13.2.5
ng-packagr                      13.2.1
rxjs                            7.5.4
typescript                      4.5.5

Anything else?

No response

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 29
  • Comments: 17 (2 by maintainers)

Commits related to this issue

Most upvoted comments

Hi, just a quick update: we plan to look into replacement APIs for the described use-case. The new API should provide an ability to create a ComponentRef instance, i.e. you should be able to do something like this:

const appRef = injector.get(ApplicationRef);
const compRef = createComponentRef(MyComponent, injector);
appRef.attachView(compRef.hostView);

We don’t have an ETA yet, but we’d make sure that it’s available before we remove ComponentFactory from the public API.

@tonysamperi the alternative is being worked on in #46685

And previously, components can be created outside components and directives. And, now that ComponentFactoryResolver is deprecated couldn’t find any alternatives for the same.

const componentFactoryResolver = injector.get(ComponentFactoryResolver);
this.applicationRef = injector.get(ApplicationRef);

const factory = componentFactoryResolver.resolveComponentFactory(MyComponent);

this.componentRef = factory.create(injector, []);
this.applicationRef.attachView(this.componentRef.hostView);

Mostly when rendering outside angular app.

Following