Reputation: 715
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
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
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
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
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