2

I'm looking for a substitute for deprecated ComponentFactoryResolver and ComponentFactory classes in Angular 13. The official documentation as well as another question here on SO suggest using ViewContainerRef, but my application instantiates Angular components in a service, outside of the DOM. There is no ViewContainerRef available.

The instantiated components are not to be shown to the user. They are used to generate in-memory SVGs that are then rasterized and used for further purposes.

This is what I've used until now in my service:

let factoryHistogram = this.resolver.resolveComponentFactory(HistogramComponent);
let newNode = document.createElement('div');
this.histogramComponent = factoryHistogram.create(this.injector, [], newNode);
this.app.attachView(this.histogramComponent.hostView);

How can I achieve the same in Angular 13?

LubosD
  • 781
  • 6
  • 18

3 Answers3

2

You can provide a service to the component then in the components constructor assign the viewRef to a variable within the service.

Stackblitz example

@Component({
  providers: [AppService],
})
export class ChildComponent {
  constructor(
    private readonly appService: AppService,
    viewRef: ViewContainerRef
  ) {
    this.appService.viewRef = viewRef;
  }

  ngOnInit() {
    this.appService.createComponent();
  }
}

Then in your service, you just create the component like this:

@Injectable()
export class AppService {
  // Assigned by the component
  viewRef!: ViewContainerRef;

  createComponent() {
    this.viewRef.createComponent(HistogramComponent);
  }
}
Get Off My Lawn
  • 34,175
  • 38
  • 176
  • 338
  • Hmm, but as I described, I don't want this component to appear anywhere. It is supposed to be disconnected from the DOM completely. – LubosD Mar 05 '22 at 18:52
  • You will always have a Angular Component somewhere such as your `AppComponent`. You need to get the view reference from a component or a directive no matter what, there is no other way to get it. – Get Off My Lawn Mar 05 '22 at 21:35
  • 2
    Well, the old code doesn't need that component, obviously. If I suddenly need to provide this to my service through such a hack, I see that as a step back. – LubosD Mar 06 '22 at 19:29
  • You could take a look at this revision and use a provider, it might help: https://stackoverflow.com/revisions/71364435/1 – Get Off My Lawn Mar 06 '22 at 20:01
2

The fact that it is no longer possible to create a component without also inserting it into DOM has been reported as a possible regression over there:

https://github.com/angular/angular/issues/45263

Hopefully the core team will be able to figure out a way to keep supporting this use case.

PowerKiKi
  • 4,539
  • 4
  • 39
  • 47
0

I have found a replacement that does not depend on providing a ViewContainerRef to the service: NullInjectorError: No provider for ViewContainerRef! in Angular Service

Disclaimer: my code creates the element to eventually insert it into de DOM. I don't think it makes it an invalid solution to this particular problem, because I create the element outside the DOM (in a service I provide in an internal component library), but just in case I will mention it.

  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jul 08 '23 at 22:38