2

I am in process on creating a small poc to try whether is it possible to load components according to a given json data structure. json will provide and array of component selectors. I tried a small example according to the reference materials i found via online. I used the "componentFactoryResolver" which is recommended way by Angular

I basically create couple of components and registered it with the entrycomponent decorator as follow in my module

entryComponents: [PersonalDetailsComponent, ContactDetailsComponent],

and in my app component i use the following code

  @ViewChild('dynamicInsert', { read: ViewContainerRef }) dynamicInsert: ViewContainerRef;
  constructor(private componentFactoryResolver: ComponentFactoryResolver) {
  }
  ngAfterViewInit() {
    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(PersonalDetailsComponent );
    const componentFactory2 = this.componentFactoryResolver.resolveComponentFactory(ContactDetailsComponent);
    this.dynamicInsert.clear();
    this.dynamicInsert.createComponent(componentFactory);
    this.dynamicInsert.createComponent(componentFactory2);
  }

and as you see i have to create component for each and every component i use. but having this an inside a loop might not be the best way to do it. i would much appreciate if any one could give me some heads up to do it in a proper way. my actual json would look like something like this

{
         "step":"1",
         "viewed":false,
         "stepDependant":{
            "parentComponent":null,
            "childComponent":null,
            "varMap":null
         },
         "widgets":[
            {
               "Component":"shipper",
               "inputs":[
                  {
                     "ServiceLine":"Export"
                  }
               ],
               "outputs":[

               ],
               "name":"Shipper Details"
            },
            {
               "Component":"shipper",
               "inputs":[
                  {
                     "ServiceLine":"Export"
                  }
               ],
               "outputs":[

               ],
               "name":"Consignee Details"
            },
            {
               "Component":"status-of-shipment",
               "inputs":[

               ],
               "outputs":[

               ],
               "name":"Status of Shipment"
            }
         ]
      }

much appreciate your inputs

Dark99
  • 81
  • 3
  • 11
  • read [Here is what you need to know about dynamic components in Angular](https://blog.angularindepth.com/here-is-what-you-need-to-know-about-dynamic-components-in-angular-ac1e96167f9e) – Max Koretskyi Oct 15 '17 at 05:57

1 Answers1

2

As you have already found the componentFactoryResolver is the correct way to create components dynamically from code. With this approach what I would do in your case is create a map or service that maps the component selectors to component types. This way you can then quickly lookup the type when you are creating the dynamic components from the JSON data. From the types you then resolve the factory and then add the components like in your sample.

If you have a predefined set of components that are known another alternative would be to define them all as <ng-template> in the parent component like this:

<ng-template #shipper><shipper ></shipper></ng-template>
<ng-template #statusOfShippment><status-of-shipment ></status-of-shipment></ng-template>

Then you can get the templates in the component by using the @ViewChild decorator.

@ViewChild('shipper')
shipperTemplate: TemplateRef<any>;
@ViewChild('statusOfShippment')
statusOfShippmentTemplate: TemplateRef<any>;

And then you can create the components in a simmilar fashion than with the factory.

this.dynamicInsert.createEmbeddedView(shipper);
this.dynamicInsert.createEmbeddedView(statusOfShippment);

What is good about this approach is that you can still have classic template binding and send a different context object to every template.

<ng-template #shipper><shipper [ServiceLine]="ServiceLine"></shipper></ng-template>

this.dynamicInsert.createEmbeddedView(shipper, {ServiceLine:"Export"});

This way you could directly send an object created from your JSON and configure the component bindings. If you use the component factory you need to set everything from code manually.

Aleš Doganoc
  • 11,568
  • 24
  • 40
  • The second way that you have mentioned seems to be mich useful for the predefined components, i never came across such solution. Thanks a heap let me try it out with the way you’ve suggested. But much appropriate if you can have couple of reference material for me to get more details about it. – Dark99 Oct 15 '17 at 01:49
  • If you look at this article ([write a structural directive](https://angular.io/guide/structural-directives#write-a-structural-directive)) from the official documentation there they use this to create a custom directive and show a template with it. Also check the official documentation for [ViewContainerRef](https://angular.io/api/core/ViewContainerRef) where it is mentioned but there are no samples unfortunately. I found a sample in some blog but cannot find it now. – Aleš Doganoc Oct 15 '17 at 17:23
  • thanks for the reference. just wanted to make a quick clarification. If we use the structural way, we have to pre define a host template right? And if we are reusing components we have to use the selector multiple times in the host view>> – Dark99 Oct 15 '17 at 17:43
  • 1
    Yes you have to predefine it inside the host component with the `` tag as I did in my original post so you can get the template definition in the code (`TemplateDef`). Then you can re use it to create multiple actual instances with the `createEmbededView` method. You reuse the same template you don't need to have multiple ones for the same component. – Aleš Doganoc Oct 15 '17 at 20:51