idekkers
idekkers

Reputation: 233

Angular 4 removing dynamically added components

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?

Upvotes: 3

Views: 10152

Answers (3)

Max Koretskyi
Max Koretskyi

Reputation: 105537

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.

Upvotes: 5

WasiF
WasiF

Reputation: 28909

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,  

  ],

Upvotes: 1

Aravind
Aravind

Reputation: 41571

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

this.container.clear();

Github source

Upvotes: 0

Related Questions