6

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!!

3
  • 2
    Unclear as to why this was down voted...I have researched, I believe my question is clear, and I believe it is useful. Commented Jun 3, 2019 at 18:18
  • 4
    Angular does not work that way. You need to use a ComponentFactoryResolver to load components dynamically angular.io/guide/dynamic-component-loader Commented Jun 4, 2019 at 7:01
  • It is better to delete your answer then question since you have resolved your issue and you can not offer the bounty to your self and before another answer came in so you will not be able to delete answered question. Commented Jun 8, 2019 at 13:59

4 Answers 4

4
+50

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

Sign up to request clarification or add additional context in comments.

5 Comments

This is a good answer and example! I did change the HTML to look like this in the example <button (click)="loadComponent()">Load Component</button> <ng-template #container> </ng-template> And moved the code that loads the component from ngOnInit() to a new function loadComponent() for a more interactive and complete answer.
I'm getting an error on "static: true" saying... Argument of type '{ static: boolean; read: typeof ViewContainerRef; }' is not assignable to parameter of type '{ read?: any; }'. Object literal may only specify known properties, and 'static' does not exist in type '{ read?: any; }'.ts(2345)
remove {static:true}. (In Angular 8 it's mandatory, In Angular 7 give error)
Okay, that's what I did and the component is loading now but when I click the button no code is executed.
this was my issue...it was just a z-index problem. Thanks for the answer!!
0

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>'

Comments

0

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

Comments

0

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.

Comments

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.