2

In my current project, we have a need for a scalable solution which will allow us to choose between multiple concrete component implementations based on server-side configuration. Without going into too much business detail, we might have multiple registration forms (RegistrationComponentA, RegistrationComponentB, RegistrationComponentC). The client is told by the server which implementation we should use.

At the moment our code might look something like this:

<registration-a [someProp]="serverValue" *ngIf="serverSays == 'a'"></registration-a>
<registration-b [someProp]="serverValue" *ngIf="serverSays == 'b'"></registration-b>
<registration-c [someProp]="serverValue" *ngIf="serverSays == 'c'"></registration-c>

Eventually, we may have 100 concrete implementations, and we want to do something more generic to avoid a template with 100 lines of *ngIf.

I would like to do something where I can just choose which component to render in the parent component itself, but from what I've been reading, using things like ComponentFactory solutions mess with change detection and require manual cleanup on destruction.

In AngularJS, I could manipulate the template and compile it on the fly and it would work fine, but with AoT, there is no compiler in the browser. (Thanks estus for pointing out that this was incorrect).

Is there an elegant way to handle this without having to manually handle change detection and lifecycle?

Craig Burton
  • 188
  • 1
  • 9
  • 2
    Possible duplicate of [How can I use/create dynamic template to compile dynamic Component with Angular 2.0?](https://stackoverflow.com/questions/38888008/how-can-i-use-create-dynamic-template-to-compile-dynamic-component-with-angular) – Estus Flask Mar 07 '18 at 20:10
  • *but with AoT, there is no compiler in the browser* - wrong, JIT compiler still can be used, but this doesn't mean that it doesn't need ComponentFactory 'mess'. – Estus Flask Mar 07 '18 at 20:12
  • It is similar, but I'm trying to avoid using the ComponentFactory stuff and all the manual paperwork that entails if possible. – Craig Burton Mar 07 '18 at 20:12
  • 2
    There wouldn't be that dupe question if this were possible. You can use somebody else's code to skip component factories and stuff, see https://github.com/patrikx3/angular-compile for example. Notice that there may be problems with AOT. – Estus Flask Mar 07 '18 at 20:15
  • 2
    ComponentFactories is the way to go. No problems with AOT as you're declaring the components (telling aot compiler to compile them), you just create them dynamically. You do need to map all the strings or whatever config values to component classes, no AOT supported way around that.. – funkizer Mar 07 '18 at 20:23

1 Answers1

0

If you don't want to manually use the component factory, you can rely on the new Angular CDK library, and it's Portal

You can set a slot (a PortalOutlet) in your parent component to display a portal in it. Think about the RouterOutlet.

<ng-template [cdkPortalOutlet]="yourPortal"></ng-template>

A portal can be a ComponentPortal or a TemplatePortal. In your case, I think you are more interested in the component one.

In your code, you can switch over your serverValue, to create the appropriate portal.

switch(serverValue) {
  case 'a':
    this.yourPortal = new ComponentPortal(RegistrationA);
    break;
  case 'b':
    this.yourPortal = new ComponentPortal(RegistrationB);
    break;
  case '...':
    // ...
}

You can read this article about CDK portal if you want to better understand its capabilities.

Since your components wont be called statically in a template, you have to let the AOT know that your component need to be compiled. To do it, you have to add this component in the entryComponents in the module that declares them.

Noémi Salaün
  • 4,866
  • 2
  • 33
  • 37