3

Using something like this: https://netbasal.com/dynamically-creating-components-with-angular-a7346f4a982d I'm adding multiple components, the question is how do I remove the components later on based on which was clicked? what I'm trying to do is create breadCrumbs, and when clicking on the crumb, remove it all all below it. to create them I use this code:

createCrumb(name, key, level){
  let data = {name:name, key:key, level,level, diagram: this.diagram};
  const factory = this.this.resolver.resolveComponentFactory(BreadCrumbsButton);
  let componentRef = this.container.createOmponent(factory);
  (<BreadCrumbsButton>componentRef.instance).data = data;
}

all this works perfectly, but I add multiples of this. the question is how do I remove specific ones while leaving the rest?

WasiF
  • 26,101
  • 16
  • 120
  • 128
idekkers
  • 223
  • 1
  • 5
  • 12

3 Answers3

5

You can call destroy method on it:

  createComponent(type) {
    this.container.clear(); 
    const factory: ComponentFactory = this.resolver.resolveComponentFactory(AlertComponent);
    this.componentRef: ComponentRef = this.container.createComponent(factory);

    setTimeout(()=>{
       this.componentRef.destroy(); <--------------------
    }, 2000);
  }

I'm using a timeout here for demonstration purposes so that a component can be seen rendered on the screen.

Max Koretskyi
  • 101,079
  • 60
  • 333
  • 488
1

Also check this answer with Demo

Dynamically ADDING and REMOVING Components in Angular


Update

You can now use subject instead of interface for components' communication

Read about RxJS Subject


Removing child components from parent so communication between them must be started but how?

Using interface in this case

What's happening ?

Parent is creating the childs and when a child tries to remove itself, it tells its parent via interface to remove it so the parent does.

import { ComponentRef, ComponentFactoryResolver, ViewContainerRef, ViewChild, Component } from "@angular/core";

// Parent Component
@Component({
    selector: 'parent',
    template: `
    <button type="button" (click)="createComponent()">
        Create Child
    </button>
    <div>
        <ng-template #viewContainerRef></ng-template>
    </div>
  `
})
export class ParentComponent implements myinterface {

    @ViewChild('viewContainerRef', { read: ViewContainerRef }) VCR: ViewContainerRef;

    //manually indexing the child components for better removal
    //although there is by-default indexing but it is being avoid for now
    //so index is a unique property here to identify each component individually.
    index: number = 0;

    // to store references of dynamically created components
    componentsReferences = [];

    constructor(private CFR: ComponentFactoryResolver) {
    }

    createComponent() {

        let componentFactory = this.CFR.resolveComponentFactory(ChildComponent);
        let componentRef: ComponentRef<ChildComponent> = this.VCR.createComponent(componentFactory);
        let currentComponent = componentRef.instance;

        currentComponent.selfRef = currentComponent;
        currentComponent.index = ++this.index;

        // prividing parent Component reference to get access to parent class methods
        currentComponent.compInteraction = this;

        // add reference for newly created component
        this.componentsReferences.push(componentRef);
    }

    remove(index: number) {

        if (this.VCR.length < 1)
            return;

        let componentRef = this.componentsReferences.filter(x => x.instance.index == index)[0];
        let component: ChildComponent = <ChildComponent>componentRef.instance;

        let vcrIndex: number = this.VCR.indexOf(componentRef)

        // removing component from container
        this.VCR.remove(vcrIndex);

        this.componentsReferences = this.componentsReferences.filter(x => x.instance.index !== index);
    }
}


// Child Component
@Component({
    selector: 'child',
    template: `
    <div>
    <h1 (click)="removeMe(index)">I am a Child, click to Remove</h1>
    </div>
    `
})
export class ChildComponent {

    public index: number;
    public selfRef: ChildComponent;

    //interface for Parent-Child interaction
    public compInteraction: myinterface;

    constructor() {
    }

    removeMe(index) {
        this.compInteraction.remove(index)
    }
}

// Interface
export interface myinterface {
    remove(index: number);
}

If you want to test this just create a file like comp.ts and paste that code in this file and add references to the app.module.ts

@NgModule({
  declarations: [

    ParentComponent,
    ChildComponent

  ],
  imports: [

    //if using routing then add like so
    RouterModule.forRoot([
      { path: '', component: ParentComponent },
      { path: '**', component: NotFoundComponent }
    ]),

  ],
  entryComponents: [

    ChildComponent,  

  ],
WasiF
  • 26,101
  • 16
  • 120
  • 128
  • I am creating tool which you can drag n drop components from sidebar to main frame we can call canvas. I cannot have loaded all components because it is not scalable. If I will have 500 components I do not want them to load at once. So I need ChildComponent class to be loaded lazily when drag n droped for first time. And also removal of unused components would be nice. But how can I load them lazily? Maybe I should study router outlet code how it does the thing. – Luckylooke Nov 22 '18 at 07:53
  • You have to study `lazy-loading in Angular`, there are lot more articles out there. I would have helped you but busy days – WasiF Nov 22 '18 at 16:32
  • thanks, I have found this https://blog.angularindepth.com/here-is-what-you-need-to-know-about-dynamic-components-in-angular-ac1e96167f9e, it is most valuable I have found so far. I ma currently playing with it. – Luckylooke Nov 23 '18 at 07:34
  • Hope, you're moving towards your goal :) – WasiF Nov 23 '18 at 17:25
0

Alternatively if you are using ViewContainerRef to hold the injected component ,you can use the clear() method .

this.container.clear();

Github source

Aravind
  • 40,391
  • 16
  • 91
  • 110