Saltar al contenido

Pestañas dinámicas con componentes elegidos por el usuario

Solución:

actualizar

Ejemplo de Angular 5 StackBlitz

actualizar

ngComponentOutlet fue agregado a 4.0.0-beta.3

actualizar

Hay un NgComponentOutlet trabajo en progreso que hace algo similar https://github.com/angular/angular/pull/11235

RC.7

Plunker ejemplo RC.7

// Helper component to add dynamic components
@Component(
  selector: 'dcl-wrapper',
  template: `
` ) export class DclWrapper @ViewChild('target', read: ViewContainerRef) target: ViewContainerRef; @Input() type: Type; cmpRef: ComponentRef; private isViewInitialized:boolean = false; constructor(private componentFactoryResolver: ComponentFactoryResolver, private compiler: Compiler) updateComponent() if(!this.isViewInitialized) return; if(this.cmpRef) // when the `type` input changes we destroy a previously // created component before creating the new one this.cmpRef.destroy(); let factory = this.componentFactoryResolver.resolveComponentFactory(this.type); this.cmpRef = this.target.createComponent(factory) // to access the created instance use // this.compRef.instance.someProperty = 'someValue'; // this.compRef.instance.someOutput.subscribe(val => doSomething()); ngOnChanges() this.updateComponent(); ngAfterViewInit() this.isViewInitialized = true; this.updateComponent(); ngOnDestroy() if(this.cmpRef) this.cmpRef.destroy();

Ejemplo de uso

// Use dcl-wrapper component
@Component(
  selector: 'my-tabs',
  template: `
  

Tabs

` ) export class Tabs @Input() tabs;
@Component(
  selector: 'my-app',
  template: `
  

Hello name

` ) export class App // The list of components to create tabs from types = [C3, C1, C2, C3, C3, C1, C1];
@NgModule(
  imports: [ BrowserModule ],
  declarations: [ App, DclWrapper, Tabs, C1, C2, C3],
  entryComponents: [C1, C2, C3],
  bootstrap: [ App ]
)
export class AppModule 

Ver también angular.io CARGADOR DE COMPONENTES DINÁMICOS

versiones mas antiguasxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Esto cambió nuevamente en Angular2 RC.5

Actualizaré el ejemplo a continuación, pero es el último día antes de las vacaciones.

Este ejemplo de Plunker demuestra cómo crear componentes dinámicamente en RC.5

Actualización: use ViewContainerRef.createComponent ()

Porque DynamicComponentLoader está en desuso, el enfoque debe actualizarse nuevamente.

@Component(
  selector: 'dcl-wrapper',
  template: `
` ) export class DclWrapper @ViewChild('target', read: ViewContainerRef) target; @Input() type; cmpRef:ComponentRef; private isViewInitialized:boolean = false; constructor(private resolver: ComponentResolver) updateComponent() if(!this.isViewInitialized) return; if(this.cmpRef) this.cmpRef.destroy(); this.resolver.resolveComponent(this.type).then((factory:ComponentFactory) => this.cmpRef = this.target.createComponent(factory) // to access the created instance use // this.compRef.instance.someProperty = 'someValue'; // this.compRef.instance.someOutput.subscribe(val => doSomething()); ); ngOnChanges() this.updateComponent(); ngAfterViewInit() this.isViewInitialized = true; this.updateComponent(); ngOnDestroy() if(this.cmpRef) this.cmpRef.destroy();

Ejemplo de Plunker RC.4
Ejemplo de Plunker beta.17

Actualización: use loadNextToLocation

export class DclWrapper 
  @ViewChild('target', read: ViewContainerRef) target;
  @Input() type;
  cmpRef:ComponentRef;
  private isViewInitialized:boolean = false;

  constructor(private dcl:DynamicComponentLoader) 

  updateComponent() 
    // should be executed every time `type` changes but not before `ngAfterViewInit()` was called 
    // to have `target` initialized
    if(!this.isViewInitialized) 
      return;
    
    if(this.cmpRef) 
      this.cmpRef.destroy();
    
    this.dcl.loadNextToLocation(this.type, this.target).then((cmpRef) => 
      this.cmpRef = cmpRef;
    );
  

  ngOnChanges() 
    this.updateComponent();
  

  ngAfterViewInit() 
    this.isViewInitialized = true;
    this.updateComponent();  
  

  ngOnDestroy() 
    if(this.cmpRef) 
      this.cmpRef.destroy();
        
  

Ejemplo de Plunker beta.17

original

No estoy del todo seguro de su pregunta cuáles son sus requisitos, pero creo que esto debería hacer lo que quiere.

los Tabs el componente obtiene un array de tipos pasados ​​y crea “pestañas” para cada elemento en el array.

@Component(
  selector: 'dcl-wrapper',
  template: `
` ) export class DclWrapper constructor(private elRef:ElementRef, private dcl:DynamicComponentLoader) @Input() type; ngOnChanges() if(this.cmpRef) this.cmpRef.dispose(); this.dcl.loadIntoLocation(this.type, this.elRef, 'target').then((cmpRef) => this.cmpRef = cmpRef; ); @Component( selector: 'c1', template: `

c1

` ) export class C1 @Component( selector: 'c2', template: `

c2

` ) export class C2 @Component( selector: 'c3', template: `

c3

` ) export class C3 @Component( selector: 'my-tabs', directives: [DclWrapper], template: `

Tabs

` ) export class Tabs @Input() tabs; @Component( selector: 'my-app', directives: [Tabs] template: `

Hello name

` ) export class App types = [C3, C1, C2, C3, C3, C1, C1];

Ejemplo de Plunker beta.15 (no basado en su Plunker)

También hay una forma de pasar datos que se pueden pasar al componente creado dinámicamente como (someData necesitaría ser pasado como type)

    this.dcl.loadIntoLocation(this.type, this.elRef, 'target').then((cmpRef) => 
  cmpRef.instance.someProperty = someData;
  this.cmpRef = cmpRef;
);

También hay algo de soporte para usar la inyección de dependencia con servicios compartidos.

Para obtener más detalles, consulte https://angular.io/docs/ts/latest/cookbook/dynamic-component-loader.html

No soy lo suficientemente bueno para los comentarios. Arreglé el plunker de la respuesta aceptada para que funcione para rc2. Nada especial, los enlaces a la CDN simplemente se rompieron, eso es todo.

'@angular/core': 
  main: 'bundles/core.umd.js',
  defaultExtension: 'js'
,
'@angular/compiler': 
  main: 'bundles/compiler.umd.js',
  defaultExtension: 'js'
,
'@angular/common': 
  main: 'bundles/common.umd.js',
  defaultExtension: 'js'
,
'@angular/platform-browser-dynamic': 
  main: 'bundles/platform-browser-dynamic.umd.js',
  defaultExtension: 'js'
,
'@angular/platform-browser': 
  main: 'bundles/platform-browser.umd.js',
  defaultExtension: 'js'
,

https://plnkr.co/edit/kVJvI1vkzrLZJeRFsZuv?p=preview

hay un componente listo para usar (compatible con rc5) ng2-steps que usa Compiler para inyectar el componente al contenedor del paso y el servicio para conectar todo (sincronización de datos)

    import  Directive , Input, OnInit, Compiler , ViewContainerRef  from '@angular/core';

import  StepsService  from './ng2-steps';

@Directive(
  selector:'[ng2-step]'
)
export class StepDirective implements OnInit

  @Input('content') content:any;
  @Input('index') index:string;
  public instance;

  constructor(
    private compiler:Compiler,
    private viewContainerRef:ViewContainerRef,
    private sds:StepsService
  )

  ngOnInit()
    //Magic!
    this.compiler.compileComponentAsync(this.content).then((cmpFactory)=>
      const injector = this.viewContainerRef.injector;
      this.viewContainerRef.createComponent(cmpFactory, 0,  injector);
    );
  


Puedes añadir valor a nuestra información contribuyendo tu experiencia en las crónicas.

¡Haz clic para puntuar esta entrada!
(Votos: 2 Promedio: 4.5)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *