1

I've created a dynamic component that I can inject templates to it from the outside. My goal is to be able to inject any template, duplicate those templates inside the component and 2 way data bind to it in order to get data changes.

It looks something like that:

@Component({
  selector: 'app-custom-container',
  templateUrl: './custom-container.component.html',
  styleUrls: ['./custom-container.component.css']
})
export class CustomContainerComponent implements OnInit {
  @Input() template: TemplateRef<any>;
  @Input() addButtonLabel: string;
  
  templates: Array<TemplateRef<any>> = [];
  constructor() { }

  ngOnInit() {
    this.templates.push(this.template);
  }
}

The HTML,I have an add button button to add more templates to itself dynamically and I have a trash button to delete templates:

<ng-container *ngFor="let template of templates; let index = index; let last = last;">
    <button type="button" (click)="templates.splice(index, 1);" class="trash-button"></button>
    <ng-container *ngTemplateOutlet="template; context:{index:index}"></ng-container>
</ng-container>
<div (click)="templates.push(template)" class="add-button">{{addButtonLabel}}</div>

I use this component like this:

<app-custom-container" [template]="tpl" addButtonLabel="ADD TEMPLATE"  addButtonClass="add-butto"></app-custom-container>
<ng-template #tpl let-index="index">
    <p-dropdown [options]="mylist" [autoWidth]="false" [(ngModel)]="myData[index]" name="myName{{index}}"
        required>
    </p-dropdown>
</ng-template>

I'm using ng-prime, thus the p-dropdown.

So what I would want is to be able to create those dynamic components, inject any template to it and be able to duplicate this template withing this dynamic component. In addition, I would want the selected data from the drop down to be inserted to my data, thus the ngModel.

Problems I have:

  • I am not sure that this is the best design for my goals. The index that is communicated back, seems pretty awkward to me.
  • Basically it is working, except for the splice part. When I'm spliceing, the data model gets new indexes after the container is being rendered again and everything is a mess, the data doesn't sits where it should. I thought about sending the data as well and have the component manage it, but I'm not sure that it's the right thing to do or even how to do it.

I would appreciate your advise and add info if something is not clear.

Update 1: Add plnkr.

As you can see, I'm adding elements and when I try to delete them, it deletes from the bottom. I must know if my basic approach is good and then to figure how to delete and update my data array accordingly.

mrgoos
  • 1,294
  • 14
  • 26
  • can you setup a plunker"? – Max Koretskyi Aug 02 '17 at 07:19
  • Added plnkr, please see above @Maximus – mrgoos Aug 02 '17 at 08:21
  • cool, I'll take a look later – Max Koretskyi Aug 02 '17 at 08:23
  • 1
    Seems you don't synchronize `myData` array with `templates`. Can you take a look at https://plnkr.co/edit/qRG4DjC0JbE8wm28sF6C?p=preview? – yurzui Aug 02 '17 at 08:40
  • You can also read `TemplateRef` through `@ContentChild` if you will declare template inside `app-custom-container` tag – yurzui Aug 02 '17 at 08:42
  • @yurzui - thanks it seems to work! I thought that the face that I'm "sending back" the `index` in the `context` should update `myData`, shouldn't it? – mrgoos Aug 02 '17 at 09:49
  • I don't think so. `myData` is array that has it's own items – yurzui Aug 02 '17 at 09:51
  • @yurzui- do you think that I should send `myData` to the custom component and let it handle the add/remove by itself? I just want to avoid to implementation of `added` and `deleted` for every `custom-container` call. WDYT? – mrgoos Aug 02 '17 at 12:01
  • Yeah it worked: https://plnkr.co/edit/VoGXCFFNz2DxzOEorwDI?p=preview Thanks a lot for your help. Please put your answer as an answer so I would be able to mark it as answered :) – mrgoos Aug 02 '17 at 12:38

0 Answers0