Funn_Bobby
Funn_Bobby

Reputation: 715

Angular 7 dynamically load @Component

I'm trying to dynamically add components to my @Component template the components are populating but the tool bar does not change when I change the "buttonstring" variable.

I have a component..

@Component({
selector: 'map-toolbar-action',
template:'<p style="position: absolute;z- 
index:5000">' + mapValues.buttonString + 
'</p>',
styleUrls: ['./map-toolbar- 
action.component.scss']
})
export class MapToolbarActionComponent 
implements OnInit {

constructor() {
mapValues.buttonString = 
mapValues.arrayToString(mapValues.buttons);
}

ngOnInit() {
}

}

I have a singleton with these elements...

public static buttonString = "<component1></component1><component2></component2><component3></component3>";

I was hoping that I could then change buttonString to add, subtract or completely replace the list of components and the toolbar would update.

buttonString = "<component2></component2><component3></component3>";
buttonString = "<component1></component1><component2></component2><component3></component3><component4></component4>";
buttonString = "<componentA></componentA><componentB></componentB><componentC></componentC>;

and that would in-turn update the components to the template but it's not working like that...how can I accomplish this?

Any help is greatly appreciated!!

Upvotes: 6

Views: 10726

Answers (4)

Mvin
Mvin

Reputation: 433

Funn_Bobby seems to have long solved this by now via *ngIf in templates. For all who are in a similar scenario though or need an even more flexible solution, I've written a library for the explicit purpose of easily loading components from strings: ngx-dynamic-hooks. Have at look at it live here. Just wanted to leave it here in case it helps someone.

Upvotes: 0

Eliseo
Eliseo

Reputation: 57929

You can not change the template using the way you're trying. the template it's read only one time at the very initial stage of the application. I suppose you can achieve it using *ngIf or "adding dynamically components" using ComponentFactoryResolver. To add dynamically a component, first, you need to declare in "entryComponents" of your module

  entryComponents:[HelloComponent]

Then, create a .html like

<ng-template #container>
</ng-template>

Your main.component.ts

  @ViewChild('container', { static: true, read: ViewContainerRef }) entry: ViewContainerRef;

  constructor(private resolver: ComponentFactoryResolver) { }

  ngOnInit()
  {
    this.entry.clear();
    const factory = this.resolver.resolveComponentFactory(HelloComponent);
    const componentRef = this.entry.createComponent(factory);
    componentRef.instance.name = this.name;
  }

See a simple example in stackblitz

Upvotes: 4

waterplea
waterplea

Reputation: 3631

If you want to dynamically add components yet unknown to you, and do so in declarative fashion, you need to use ngComponentOutlet:

https://angular.io/api/common/NgComponentOutlet

You would need to add your component to entryComponents of some module and then pass it to ngComponentOutlet. If you are using lazy modules — make sure you pass Injector that's aware of that entryComponents, see:

https://angular.io/api/common/NgComponentOutlet

Upvotes: 0

Funn_Bobby
Funn_Bobby

Reputation: 715

It appears that you can load components initially using "template"

template:'<p style="position: absolute;z-index:5000">' + components + '</p>'
**Global variable somewhere
public static components = "<component1></component1><component2></component2> 
<component3></component3>"

You cannot use 2 way binding to change this string and dynamically populate components. I couldn't figure out how to get ComponentFactoryResolver to meet my needs so... What I've done is handle this with a global state variable and *ngIf in the parent component toolbar html that contains my tool components

<p *ngIf="myAppStateValue ==='foo'">
<component-one></component-one>
<component-two></component-two>
<component-three></component-three>
</p>
<p *ngIf="myAppStateValue ==='bar'">
<component-three></component-three>
<component-four></component-four>
<component-five></component-five>
</p>

Then I also added an *ngIf to the Parent application html that loads the tool bars

 <div *ngIf="formValues.mapState !='custom'"><toolbar-1></toolbar-1> 
 </div>
 <div *ngIf="formValues.mapState =='custom'"><custom-toolbar></custom-toolbar></div>

When the app loads it loads the global "components" variable with whatever the user has determined they want their "custom" tools to be.

public static components = "<component1></component1><component2></component2> 
<component3></component3>"

and then in the custom toolbar i use the "template" parameter to load the components

template:'<p style="position: absolute;z-index:5000">' + components + '</p>'

Upvotes: 0

Related Questions