0

I have an angular 1.x app which works with a dynamic layout. The app receives a layout json with the screen's metadata and simply, generates compiled components on the fly and creates a screen.

The relevant "important code" looks like this:

const element = this.$compile(`<${this.control.type} control="control" data="data"></${this.control.type}>`)(scope);
this.$element.replaceWith(element);

Now, I'm trying to migrate this to Angular 5 and I've understood that Angular 5 dropped the DOM manipulation and the $compile functionality.

I've searched all around and found solutions that know how to render dynamic html (e.g. {{1+1}}) and other deprecated stuff (prior to Angular 5), but couldn't find a fit for rendering dynamic made components (and handling their inner bindings).

Is there any way I can accomplish this kind of functionality

3
  • what you're trying to achieve is still possible in Angular, read this article Here is what you need to know about dynamic components in Angular and this answer to get an idea of what you will have to go through Commented Nov 30, 2017 at 18:08
  • however, I wouldn't advice going that path. I had the same strategy in AngluarJS, but once we migrated to Angular we started keeping all references to the components in a service and when needed we now insert them manually. The article I linked shows how to manually manipulate the components. Commented Nov 30, 2017 at 18:10
  • @AngularInDepth.com - I was looking for something a bit different (compiling an existing component with bindings on the fly). My main problem was to convert the component's string name into a type. This link has a very similar use case: blog.angular.cool/2016/11/dynamic-components-with.html Currently, that's the path I took. I've created an extra string-type mapping object and created the dynamic components on the fly with their injectable bindings. Commented Nov 30, 2017 at 20:22

1 Answer 1

1

This is the way to create a component by your self like angularJS: (Don't forget to destroy it! call destroy() on the componentRef to do this)

Parent Component:

@ViewChild('componentHolder', { read: ViewContainerRef }) componentHolder: ViewContainerRef;

constructor(private componentFactoryResolver: ComponentFactoryResolver) { }
public createComponent(): void {
          const componentFactory = this.componentFactoryResolver.resolveComponentFactory(MyComponent);
          const componentRef = this.componentHolder.createComponent(componentFactory);
}

Parent Component HTML:

<button (click)="createComponent()">Add New MyComponent below</button>
<div #componentHolder ></div>

Add the MyComponent in the NgModule:

...
  imports: [
    BrowserModule,
    FormsModule,
    RouterModule.forRoot(appRoutes),
  ],
  entryComponents: [
    MyComponent
  ],...
Sign up to request clarification or add additional context in comments.

7 Comments

this.componentFactoryResolver.resolveComponentFactory(MyComponent); - This line is a problem for me. As you can see in my example, I'm trying to resolve a control's type from a string. Thanks for the reply.
You need to pass a Type<any> Object to the resolveComponentFactory, what you can do is to create a Factory / map that resolves the string into the Type<any> like 'MyComponent' => MyComponent otherwise is no other option to do this, if you look to the angular router in the routerConfig you need to give the class Type<any> as well.
This is my workaround for now (plus adding those components as entryComponents). I still have one issue with injecting @Input()'s to the dynamic component - do you know how to achieve that?
Found my bug, I've created the component on the ngViewAfterInit and not on ngOnInit and that's why nothing got rendered. Here's a pretty nice link that creates something similar to what I tried to create: blog.angular.cool/2016/11/dynamic-components-with.html +1 - Thanks for your help!! I still think this is a little work around and I was looking for something more complete - so additional answers will be more than accepted :)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.