Home > Software design >  Create and Remove Components Dynamically in Angular 13
Create and Remove Components Dynamically in Angular 13

Time:12-04

I want to delete child component, parent will delete the last child only and after that, it shows that index is -1 from hostView and can't delete the child from view

this is my Child View

<button (click)="remove_me()" >I am a Child {{unique_key}}, click to Remove
</button>

this is my Child Component

import { Component } from '@angular/core';
import { ParentComponent } from '../parent/parent.component';

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css'],
})
export class ChildComponent {
  public unique_key: number;
  public parentRef: ParentComponent;

  constructor() {}

  remove_me() {
    console.log(this.unique_key);
    this.parentRef.remove(this.unique_key);
  }
}

this is my Parent View

<button type="button" (click)="AddChild()">
I am Parent, Click to create Child
</button>
<div>
<ng-template #viewContainerRef></ng-template>
</div>

this is my Parent Component

import {
  ComponentRef,
  ViewContainerRef,
  ViewChild,
  Component,
} from '@angular/core';
import { ChildComponent } from '../child/child.component';

@Component({
  selector: 'app-parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.css'],
})
export class ParentComponent {
  @ViewChild('viewContainerRef', { read: ViewContainerRef })
  vcr!: ViewContainerRef;
  ref!: ComponentRef<ChildComponent>;

  child_unique_key: number = 0;
  componentsReferences = Array<ComponentRef<ChildComponent>>();

  constructor() {}

  AddChild() {
    this.ref = this.vcr.createComponent(ChildComponent);
    let childComponent = this.ref.instance;
    childComponent.unique_key =   this.child_unique_key;
    childComponent.parentRef = this;
  }

  remove(key: number) {
    const index = this.vcr.indexOf(this.ref.hostView);
    console.log(index);
    if (index != -1) {
      this.vcr.remove(index);
    }
    // removing component from the list
    this.componentsReferences = this.componentsReferences.filter(
      (x) => x.instance.unique_key !== key
    );
  }
}

I tried the methods from older Angular versions that supports ComponentFactoryResolver, but I want to upgrade the version of Angular

CodePudding user response:

There are some obvious errors in your code:

  • You initialize a property componentsReferences = Array<ComponentRef<ChildComponent>>(); but never populate it.
  • even if you filter out that element from that list you dont remove it from the view-container. Which is why angular wont remove the component. (https://angular.io/guide/dynamic-component-loader)

But I have to say that there are quite some more issues with your code. You should never ever have a ref from your child-component to your parent component for example.

I suggest you have a look at and follow through with the angular tour of heros because dynamic component creation is quite a complex topic and it seems that you should stick to some basics first.

For example could your desired outcome be done kinda like this:

export class ParentComponent {
  uniqueKeys: number [] = [];
  private counter = 0; 

  addKey() {
    this.uniqueKeys.push(this.counter);
    this.counter  ;
  }

  removeLastKey() {
    this.uniqueKeys.pop();
  }
}

in parent-component.html:

  <app-child *ngFor="let key of uniqueKeys" [key]=key></app-child>

and in child-component.html you can have your @Input() for the key property if needed... Just check https://angular.io/tutorial

CodePudding user response:

To remove a child component in Angular, you can use the ViewContainerRef class. In your ParentComponent, you can inject ViewContainerRef in the constructor and use its remove() method to remove the child component. The remove() method takes the index of the child component in the view container as its argument. You can use the indexOf() method to get the index of the child component.

Here is an example of how you can use ViewContainerRef to remove a child component in Angular:

import { ViewContainerRef } from '@angular/core';

@Component({
  selector: 'app-parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.css'],
})
export class ParentComponent {
  @ViewChild('viewContainerRef', { read: ViewContainerRef })
  vcr!: ViewContainerRef;

  constructor(private vcRef: ViewContainerRef) {}

  remove() {
    const index = this.vcr.indexOf(this.ref.hostView);

    if (index != -1) {
      this.vcr.remove(index);
    }
  }
}

In the remove() method, you can use the indexOf() method to get the index of the child component in the view container and then use the remove() method to remove the child component from the view container.

You can then call the remove() method from the child component when the user clicks the button to remove the child component.

Here is an example of how you can call the remove() method from the child component:

import { Component } from '@angular/core';
import { ParentComponent } from '../parent/parent.component';

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css']
})
export class ChildComponent {
  public unique_key: number;
  public parentRef: ParentComponent;

  constructor() {
  }

  remove_me() {
    console.log(this.unique_key)
    this.parentRef.remove();
  }
}

In the remove_me() method, you can call the remove() method on the parentRef property to remove the child component.

I hope this helps!

  • Related