style img attribute html angular typescript

img - title html



AGREGAR y QUITAR componentes dinĂ¡micamente en angular (2)

Los documentos oficiales actuales solo muestran cómo cambiar dinámicamente componentes dentro de una etiqueta <ng-template> . https://angular.io/guide/dynamic-component-loader

Lo que quiero lograr es, digamos que tengo 3 componentes: header , section y footer con los siguientes selectores:

<app-header> <app-section> <app-footer>

Y luego hay 6 botones que agregarán o eliminarán cada componente: Add Header , Add Section y Add Footer

y cuando hago clic en Add Header , la página agregará <app-header> a la página que lo muestra, por lo que la página contendrá:

<app-header>

Y luego, si hago clic en Add Section dos veces, la página ahora contendrá:

<app-header> <app-section> <app-section>

Y si hago clic en Add Footer , la página ahora contendrá todos estos componentes:

<app-header> <app-section> <app-section> <app-footer>

¿Es posible lograr esto en Angular? Tenga en cuenta que ngFor no es la solución que estoy buscando, ya que solo permite agregar los mismos componentes, no componentes diferentes a una página.

EDITAR: ngIf y ngFor no es la solución que estoy buscando, ya que las plantillas ya están predeterminadas. Lo que estoy buscando es algo así como una pila de componentes o una matriz de componentes donde podamos agregar, eliminar y cambiar cualquier índice de la matriz fácilmente.

EDIT 2: para que quede más claro, tengamos otro ejemplo de por qué ngFor no funciona. Digamos que tenemos los siguientes componentes:

<app-header> <app-introduction> <app-camera> <app-editor> <app-footer>

Ahora aquí viene un nuevo componente, <app-description> , que el usuario quiere insertar entre y <app-editor> . ngFor solo funciona si hay un mismo componente que quiero repetir una y otra vez. Pero para diferentes componentes, ngFor falla aquí.


He creado una demostración para mostrar el proceso dinámico de agregar y quitar. El componente principal crea los componentes secundarios dinámicamente y los elimina.

Haga clic para ver la demostración

Componente principal

import { ComponentRef, ComponentFactoryResolver, ViewContainerRef, ViewChild, Component } from "@angular/core"; @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); } }

Componente hijo

@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); }

agregar referencias a app.module.ts

@NgModule({ declarations: [ ParentComponent, ChildComponent ], imports: [ //if using routing then add like so RouterModule.forRoot([ { path: '''', component: ParentComponent } ]), ], entryComponents: [ ChildComponent, ],


Lo que está tratando de lograr se puede hacer creando componentes dinámicamente usando ComponentFactoryResolver y luego inyectándolos en ViewContainerRef . Una forma de hacer esto dinámicamente es pasar la clase del componente como un argumento de su función que creará e inyectará el componente.

Ver ejemplo a continuación:

import { Component, ComponentFactoryResolver, Type, ViewChild, ViewContainerRef } from ''@angular/core''; // Example component (can be any component e.g. app-header app-section) import { DraggableComponent } from ''./components/draggable/draggable.component''; @Component({ selector: ''app-root'', template: ` <!-- Pass the component class as an argument to add and remove based on the component class --> <button (click)="addComponent(draggableComponentClass)">Add</button> <button (click)="removeComponent(draggableComponentClass)">Remove</button> <div> <!-- Use ng-template to ensure that the generated components end up in the right place --> <ng-template #container> </ng-template> </div> ` }) export class AppComponent { @ViewChild(''container'', {read: ViewContainerRef}) container: ViewContainerRef; // Keep track of list of generated components for removal purposes components = []; // Expose class so that it can be used in the template draggableComponentClass = DraggableComponent; constructor(private componentFactoryResolver: ComponentFactoryResolver) { } addComponent(componentClass: Type<any>) { // Create component dynamically inside the ng-template const componentFactory = this.componentFactoryResolver.resolveComponentFactory(componentClass); const component = this.container.createComponent(componentFactory); // Push the component so that we can keep track of which components are created this.components.push(component); } removeComponent(componentClass: Type<any>) { // Find the component const component = this.components.find((component) => component.instance instanceof componentClass); const componentIndex = this.components.indexOf(component); if (componentIndex !== -1) { // Remove component from both view and array this.container.remove(this.container.indexOf(component)); this.components.splice(componentIndex, 1); } } }

Notas:

  1. Si desea facilitar la eliminación de los componentes más adelante, puede realizar un seguimiento de ellos en una variable local, consulte this.components . Alternativamente, puede recorrer todos los elementos dentro de ViewContainerRef .

  2. Debe registrar su componente como componente de entrada. En la definición de su módulo, registre su componente como entryComponent ( entryComponents: [DraggableComponent] ).

Ejemplo de ejecución: https://plnkr.co/edit/mrXtE1ICw5yeIUke7wl5

Para más información: https://angular.io/guide/dynamic-component-loader