5

I'm new to Angular. I have a button that every time I click it, it creates a component dynamically. I need each component to have a button or something that can destroy that component specifically. I have a function in the dynamic component that when I click on it, that component must be closed, but I don't know how to pass it to the function of the typescript file.Please help me.

app.component.ts

import { Component, OnInit, ComponentFactoryResolver, ViewChild, Input,ComponentRef,ViewContainerRef } from '@angular/core';
import {ChatService} from "./services/chat.service";
import {Mensaje} from "./models/mensaje";
import {ConversacionComponent} from "./components/conversacion/conversacion.component";
import {ConversacionDirective} from "./components/conversacion/conversacion.directive";

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
    providers:[ChatService]
})
export class AppComponent {
    @ViewChild(ConversacionDirective, {static: true}) eldinamico: ConversacionDirective;
  title = 'chat';

  constructor(private cfr: ComponentFactoryResolver){  }
    ngOnInit() { }


    componenteDinamico(mensaje: string) {
        const cf = this.cfr.resolveComponentFactory(ConversacionComponent);
        const vcr = this.eldinamico.viewContainerRef;
        vcr.createComponent(cf, 0);
    }
}

conversacion.directive.ts

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

@Directive({
    selector: '[appConversacionDinamica]'
})
export class ConversacionDirective {

    constructor(public viewContainerRef: ViewContainerRef) { }

}

app.component.html

<input type="text" #mensaje><br/>
<button (click)="componenteDinamico(mensaje.value)"> Crear Componente </button>
<br/>
<div class="orden">
  <ng-template appConversacionDinamica></ng-template>

</div>

conversacion.component.html


<button (click)="removeObject()">delete me</button>
<div>
    this is a component dynamically
</div>

conversacion.component.ts

import {Component, Input, OnInit, Output, EventEmitter,ViewChild,ElementRef,ComponentRef} from '@angular/core';

@Component({
  selector: 'app-conversacion',
  templateUrl: './conversacion.component.html',
  styleUrls: ['./conversacion.component.css']
})
export class ConversacionComponent implements OnInit {
    mensaje: string;   
    vcr:any; 

  constructor() {}

  ngOnInit() {}   

  removeObject(){
    this.vcr.destroy();
    }
}

1 Answer 1

6

Below is an example where the dynamic component can "delete itself". The creator (app.component.ts) subscribes to the output of the dynamic component (simple.component.ts) and then invokes .destroy().

Also, the SimpleComponent has to be included in the module as an entryComponent since it is created dynamically.

Giphy: https://giphy.com/gifs/W2zx2dhNk4znnYFyGT

Example:


app.component.html

<h1>App</h1>
<button (click)="onClickAdd()">Create</button>

<br>
<hr>
<ng-template #componentsContainer></ng-template>

app.component.ts

import {
  Component,
  ViewChild,
  ViewContainerRef,
  ComponentFactoryResolver,
  ComponentRef,
  OnDestroy
} from '@angular/core';
import { Subscription } from 'rxjs';
import { tap } from 'rxjs/operators';
import { SimpleComponent } from './simple/simple.component';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnDestroy {
  @ViewChild('componentsContainer', { read: ViewContainerRef }) container: ViewContainerRef;
  private subs: Subscription[] = [];

  ngOnDestroy() {
    // unsubscribe from all on destroy
    this.subs.forEach(sub => sub.unsubscribe());
  }

  onClickAdd = () => {
    const factory = this.componentFactoryResolver.resolveComponentFactory(SimpleComponent);
    const component = this.container.createComponent(factory);

    component.instance.numberCreated = this.container.length;

    // subscribe to component event to know when to delete
    const selfDeleteSub = component.instance.deleteSelf
      .pipe(tap(() => component.destroy()))
      .subscribe();

    // add subscription to array for clean up
    this.subs.push(selfDeleteSub);
  }

  constructor(private componentFactoryResolver: ComponentFactoryResolver) {}
}

simple.component.html

<button (click)="deleteSelf.emit()" style="background-color: blue; color: white">delete self</button>
<p>Dynamic Component</p>
<p>Number at time of creation: {{ numberCreated }}</p>
<hr>

simple.component.ts

import { Component, OnInit, Output, EventEmitter, Input } from '@angular/core';

@Component({
  selector: 'app-simple',
  templateUrl: './simple.component.html',
  styleUrls: ['./simple.component.css']
})
export class SimpleComponent implements OnInit {
  @Output() deleteSelf: EventEmitter<void> = new EventEmitter<void>();
  @Input() numberCreated: number;

  constructor() { }

  ngOnInit() {
  }

}

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { SimpleComponent } from './simple/simple.component';

@NgModule({
  declarations: [AppComponent, SimpleComponent],
  imports: [BrowserModule, AppRoutingModule],
  providers: [],
  bootstrap: [AppComponent],
  entryComponents: [SimpleComponent]
})
export class AppModule {}

Sign up to request clarification or add additional context in comments.

8 Comments

I know what do yo say,but in my scenario I don't know how to do it,could you show me please?
Hey Jesus, I updated the answer to include a working example. Let me know if it makes sense.
Its works!,but I get an error on a line, I copied exactly your code just by replacing the word SimpleComponent with ConversacionComponent and the file paths. I get an error in the line of ViewChild ."Argument of type {read: ViewContainerRef } is not assignable to parameter of type {'read?:any;static;boolean'}Property 'static' is missing in type {read type of ViewContainerRef } but required in type {'read?:any;static;boolean'} "
Why show me the line of View Child like an error specifically in {read: ViewContainerRef} ?
hmm, are you importing ViewChild and ViewContainerRef from @angular/core?
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.