Joao Garin
Joao Garin

Reputation: 573

Angular 2 - Load a component dynamically from a string

I am building an app that statically analyses components (from an angular app) and renders them in a angular app, sort of a style guide but with more information where it has information on inputs and other aspects of the component etc..

The app uses webpack and analyzes a component and returns to a "frontend" (another angular app) information about a component including its source code and I want to render this component in that app.

Dynamic component loader requires that you have imported the component and have a reference to it (Type), which I don't have as this information is passed to the app at runtime.

I am a bit stuck on how to render this, does angular2 have some sort of mechanism to compile from a string? using some sort of code generation, or maybe there is a better way to go at it?

To be more clear I have :

{
"id": 0,
"name": "carte-blanche-angular2",
"kind": 0,
"flags": {},
"children": [
    {
        "id": 1,
        "name": "\"component\"",
        "kind": 1,
        "kindString": "External module",
        "flags": {
            "isExported": true
        },
        "originalName": "node_modules/carte-blanche-angular2/tmp/component.ts",
        "children": [
            {
                "id": 2,
                "name": "NameComponent",
                "kind": 128,
                "kindString": "Class",
                "flags": {
                    "isExported": true
                },
                "decorators": [
                    {
                        "name": "Component",
                        "type": {
                            "type": "reference",
                            "name": "Component"
                        },
                        "arguments": {
                            "obj": "{\n    selector: 'cb-name', // <name></name>\n    styles: [`\n    div{\n        color: red; \n        font-style:italic;\n    }\n    `],\n    // The template for our name component\n    template: `\n    <div>name : {{name}}</div>\n    `\n}"
                        }
                    }
                ],
                "children": [
                    {
                        "id": 4,
                        "name": "constructor",
                        "kind": 512,
                        "kindString": "Constructor",
                        "flags": {
                            "isExported": true
                        },
                        "signatures": [
                            {
                                "id": 5,
                                "name": "new NameComponent",
                                "kind": 16384,
                                "kindString": "Constructor signature",
                                "flags": {},
                                "type": {
                                    "type": "reference",
                                    "name": "NameComponent",
                                    "id": 2
                                }
                            }
                        ]
                    },
                    {
                        "id": 3,
                        "name": "name",
                        "kind": 1024,
                        "kindString": "Property",
                        "flags": {
                            "isExported": true
                        },
                        "decorators": [
                            {
                                "name": "Input",
                                "type": {
                                    "type": "reference",
                                    "name": "Input"
                                },
                                "arguments": {}
                            }
                        ],
                        "type": {
                            "type": "instrinct",
                            "name": "string"
                        }
                    }
                ],
                "groups": [
                    {
                        "title": "Constructors",
                        "kind": 512,
                        "children": [
                            4
                        ]
                    },
                    {
                        "title": "Properties",
                        "kind": 1024,
                        "children": [
                            3
                        ]
                    }
                ]
            }
        ],
        "groups": [
            {
                "title": "Classes",
                "kind": 128,
                "children": [
                    2
                ]
            }
        ]
    }
],
"groups": [
    {
        "title": "External modules",
        "kind": 1,
        "children": [
            1
        ]
    }
]
}

Which is the generated typedoc of :

"{
"id": 0,
"name": "carte-blanche-angular2",
"kind": 0,
"flags": {},
"children": [
    {
        "id": 1,
        "name": "\"component\"",
        "kind": 1,
        "kindString": "External module",
        "flags": {
            "isExported": true
        },
        "originalName": "node_modules/carte-blanche-angular2/tmp/component.ts",
        "children": [
            {
                "id": 2,
                "name": "NameComponent",
                "kind": 128,
                "kindString": "Class",
                "flags": {
                    "isExported": true
                },
                "decorators": [
                    {
                        "name": "Component",
                        "type": {
                            "type": "reference",
                            "name": "Component"
                        },
                        "arguments": {
                            "obj": "{\n    selector: 'cb-name', // <name></name>\n    styles: [`\n    div{\n        color: red; \n        font-style:italic;\n    }\n    `],\n    // The template for our name component\n    template: `\n    <div>name : {{name}}</div>\n    `\n}"
                        }
                    }
                ],
                "children": [
                    {
                        "id": 4,
                        "name": "constructor",
                        "kind": 512,
                        "kindString": "Constructor",
                        "flags": {
                            "isExported": true
                        },
                        "signatures": [
                            {
                                "id": 5,
                                "name": "new NameComponent",
                                "kind": 16384,
                                "kindString": "Constructor signature",
                                "flags": {},
                                "type": {
                                    "type": "reference",
                                    "name": "NameComponent",
                                    "id": 2
                                }
                            }
                        ]
                    },
                    {
                        "id": 3,
                        "name": "name",
                        "kind": 1024,
                        "kindString": "Property",
                        "flags": {
                            "isExported": true
                        },
                        "decorators": [
                            {
                                "name": "Input",
                                "type": {
                                    "type": "reference",
                                    "name": "Input"
                                },
                                "arguments": {}
                            }
                        ],
                        "type": {
                            "type": "instrinct",
                            "name": "string"
                        }
                    }
                ],
                "groups": [
                    {
                        "title": "Constructors",
                        "kind": 512,
                        "children": [
                            4
                        ]
                    },
                    {
                        "title": "Properties",
                        "kind": 1024,
                        "children": [
                            3
                        ]
                    }
                ]
            }
        ],
        "groups": [
            {
                "title": "Classes",
                "kind": 128,
                "children": [
                    2
                ]
            }
        ]
    }
],
"groups": [
    {
        "title": "External modules",
        "kind": 1,
        "children": [
            1
        ]
    }
]
}"

Which is the string I mentioned.

Thanks,

Best regards Joao Garin

Upvotes: 3

Views: 2198

Answers (1)

You could index this component as string in a service, something like this:

export class ComponentIndexerService{
private clazzNames: Array<string>;
classes: Array<new (...args:any[]) => any>

public registerComponent(componentName : string, componentClass : new (...args[]) => any)
  {
     this.classNames.push(componentName);
     this.classes.push(componentClass);
  }
}

public get(componentName : string) {
    let index : number = this.classNames.indexOf(componentName);
    if(index > -1) {
        return this.classes[index];
    }
}

Then register:

componentIndexerService.register("someName", ComponentClass);
componentIndexerService.register("someName2", ComponentClass2);
componentIndexerService.register("someName3", ComponentClass3);

And Finally use:

constructor(dcl: DynamicComponentLoader, viewContainerRef: ViewContainerRef, componentIndexerService : ComponentIndexerService) {
    let clazz : (...args:[]) => any = componentIndexerService.get("someName");
    dcl.loadNextToLocation(clazz, viewContainerRef);
}

Upvotes: 1

Related Questions