Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
459 views
in Technique[技术] by (71.8m points)

Angular – Dynamically load multiple instances of the same component by submitting a form to add a new instance of a component to the display

Problem

I’m trying to dynamically load multiple instances of the same component, with a new component being added/loaded to the screen when a user submits a form. The idea behind this is that a user can provide details on the form that is then displayed on that particular instance of that component that is created.

My initial idea was to have some sort of data structure such as an array or map for key pair values, whereby I could add a new instance of my component alongside the form data to my data structure when the user submits the form. Then angular could somehow display every instance of a component that resides in the data structure like the following image below:

enter image description here

It’s important to note that the form is actually its own separate component that’s in the form of modal dialog. This form dialog is opened when the green Add Status Box button is pressed, then the user can submit the form and (hopefully) be able to create a new instance of the status box component with the data provided from the submitted form.

However this is proving difficult, currently the way I’m achieving this in the screenshot above is by merely displaying each component individually in the app.component.html, which isn’t dynamic at all and has no user control:

<app-header></app-header>
<div class='status-box-container'>
    <app-status-box></app-status-box> //component I’m trying to display
    <app-status-box></app-status-box> //component I’m trying to display
    <app-status-box></app-status-box> //component I’m trying to display
</div>

Things I’ve tried

I’ve followed a few tutorials already but either the outcome of the said tutorial doesn’t quite do what I’m asking, doesn’t work at all or it’s too complicated for me to understand.

First I tried to follow this official guide from the Angular website but this only displays one component at a time and dynamically changes its content every 3 seconds rather than displaying multiple instances of one component at the same time.

Next, I tried to follow this stackblitz from this existing stack overflow question, but I found this to not work and to be very complicated, most of which I didn’t understand. Although it’s quite close to what I’m trying to achieve.

Lastly, I tried to follow this stackblitz I found, but it’s not as dynamic as I want it to be because each instance of the component is hardcoded into different variables, I also couldn't get it to work.

Observations

One thing I have noticed though is that all three approaches have two parts in common. Firstly in the app.component.html they either use <ng-container #messageContainer></ng-container> or <ng-template #messageContainer></ng-template>. To my understanding, this is where the dynamic components would be loaded into the html template.

The second part in app.component.ts usually looks something like this:

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

constructor (private cfr: ComponentFactoryResolver) { }

private createComponent (compClass) 
{
  const compFactory = this.cfr.resolveComponentFactory(compClass);
  return this.messageContainer.createComponent(compFactory);;
}

private loadNewComponentList () 
{
  this.messages.forEach((msg, idx) => 
  {
    this.destroyCompFromList(this.componentList[idx]);
    const comp = this.createComponent(componentMap[this._crtComp]);

    (comp.instance as any).message = msg;

    comp.changeDetectorRef.detectChanges();

    this.componentList[idx] = comp;
  });
}

This is taken from the first tutorial I tried.

Now I don’t really understand what this code does, but from looking at it, it seems as though the ComponentFactoryResolver would be responsible for creating multiple instances of identical components. And the ViewContainerRef seems to be what’s used in the html template.

This seems to be the direction I should head in but I don’t understand what these imported classes do, and I’m not even sure if this approach would be suitable for my specific requirements.

I was hoping someone could show me a simple solution to this problem, or at least adapt/simplify the tutorials to meet my specific requirements.

Thanks.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You're on the right track. To briefly sum up the official guide from Angular you should create a directive to easily get the ViewContainerRef of an HTML element - the component will be injected as a sibling to this. Then use ComponentFactoryResolver to create your components when needed.

Personally would make directive the responsible for also creating the component since it allows you to easily use it with an *ngFor and separate all the dynamic stuff from the regular components

@Directive({
    selector: '[appDynamicStatusBox]'
})
export class DynamicStatusBoxDirective implements OnInit, OnDestroy {
    @Input() config: MyData;

    componentRef: ComponentRef<StatusBoxComponent>;

    constructor(private resolver: ComponentFactoryResolver, public viewContainerRef: ViewContainerRef) {}

    ngOnInit(): void {
        const factory = this.resolver.resolveComponentFactory(StatusBoxComponent);
        this.viewContainerRef.clear();
        this.componentRef = this.viewContainerRef.createComponent(factory);
        this.componentRef.instance.someProperty= this.config.prop1;
        this.componentRef.instance.someOtherProperty= this.config.prop2;
    }

    ngOnDestroy(): void {
        this.componentRef.destroy();
    }
}
<ng-container *ngFor="let config of myConfigs; let i=index" appDynamicStatusBox [config]="config[i]"></ng-container>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...