2

I am creating a page which is like a form creator. The user will click and add different components into the page, which will add entries into the "component" variable as so:

Example for Component1:

const childComponent = this.componentFactoryResolver.resolveComponentFactory(Component1);
this.components.push(childComponent);

So the components array will have a collection of ComponentFactory elements.

I am then creating components dynamically and conditionally in HTML as follows:

<div cdkDropList class="example-list" style="margin: 20px" (cdkDropListDropped)="drop($event)">
    <div cdkDrag *ngFor="let cmp of components">
        <ng-container *ngIf="cmp.componentType.name=='Component1'">
            <app-Component1></app-Component1>
        </ng-container>
        <ng-container *ngIf="cmp.componentType.name=='Component2'">
            <app-Component2></app-Component2>
        </ng-container>
        <ng-container *ngIf="cmp.componentType.name=='Component3'">
            <app-Component3></app-Component3>
        </ng-container>

    </div>
</div>

Works fine so far. Now, when the user clicks the save button, it should get a list of all the components on the page. I need it in the end as the components are editable, so the values will change. the list "components" cannot be used as it only contains the Factory elements.

Is it possible to get the component instance that gets declared in HTML? I am trying @ViewChildren, but I might need to add it for every component type, so I wont get it in the order it was added by the user.

Finally, I have tried to create the component in code and then add it to the page using ComponetFactoryResolver. However, each of them needs to have the directive "cdkDrag" declared within it, which becomes impossible using that approach.

Thanks.

Groben
  • 1,374
  • 2
  • 10
  • 29
javapyscript
  • 720
  • 8
  • 22

1 Answers1

2

When using a loop, the template reference variables can refer to several items.

This is shown in this stackblitz and as you can see, both elements have the correct class instance.

Hope this helps !

<ng-container *ngFor="let i of [0, 1]; last as isLast; first as isFirst">
  <hello *ngIf="isFirst" #child name="{{ name }}"></hello>
  <goodbye *ngIf="isLast" #child name="{{ name }}"></goodbye>
</ng-container>

<p>
  Start editing to see some magic happen :)
</p>
import { Component, ViewChildren, QueryList } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  name = 'Angular';

  @ViewChildren('child') children: QueryList<any>;

  ngOnInit() {
    setTimeout(() => console.log(this.children.first), 1000);
    setTimeout(() => console.log(this.children.last), 1000);
  }
}

LOG

HelloComponent
    name: "Angular"
    __proto__: Object
GoodbyeComponent
    name: "Angular"
    __proto__: Object
  • Genius! Good to know that ViewChildren picks up template reference variables too. I can now set all components with the same ref and get all of them in order. Thank you! – javapyscript May 15 '19 at 07:29