Zoeken…


Een wrapper-component die declaratieve dynamische componenten toevoegt

Een aangepaste component die het type van een component als invoer neemt en een instantie van dat componenttype in zichzelf maakt. Wanneer de invoer wordt bijgewerkt, wordt de eerder toegevoegde dynamische component verwijderd en in plaats daarvan de nieuwe toegevoegd.

@Component({
  selector: 'dcl-wrapper',
  template: `<div #target></div>`
})
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 < any > ) => {
      this.cmpRef = this.target.createComponent(factory)
        // to access the created instance use
        // this.cmpRef.instance.someProperty = 'someValue';
        // this.cmpRef.instance.someOutput.subscribe(val => doSomething());
    });
  }

  ngOnChanges() {
    this.updateComponent();
  }

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

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

Hiermee kunt u dynamische componenten zoals maken

<dcl-wrapper [type]="someComponentType"></dcl-wrapper>

Plunker-voorbeeld

Dynamisch component toevoegen aan specifieke gebeurtenis (klik)

Hoofdcomponentbestand:

//our root app component
import {Component, NgModule, ViewChild, ViewContainerRef, ComponentFactoryResolver, ComponentRef} from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'
import {ChildComponent} from './childComp.ts'

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>Hello {{name}}</h2>
      <input type="button" value="Click me to add element" (click) = addElement()> // call the function on click of the button
      <div #parent> </div> // Dynamic component will be loaded here
    </div>
  `,
})
export class App {
  name:string;
  
  @ViewChild('parent', {read: ViewContainerRef}) target: ViewContainerRef;
  private componentRef: ComponentRef<any>;

  constructor(private componentFactoryResolver: ComponentFactoryResolver) {
    this.name = 'Angular2'
  }
  
  addElement(){
    let childComponent = this.componentFactoryResolver.resolveComponentFactory(ChildComponent);
    this.componentRef = this.target.createComponent(childComponent);
  }
}

childComp.ts:

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

@Component({
  selector: 'child',
  template: `
    <p>This is Child</p>
  `,
})
export class ChildComponent {
  constructor(){
    
  }
}

app.module.ts:

@NgModule({
  imports: [ BrowserModule ],
  declarations: [ App, ChildComponent ],
  bootstrap: [ App ],
  entryComponents: [ChildComponent] // define the dynamic component here in module.ts
})
export class AppModule {}

Plunker-voorbeeld

Dynamisch gecreëerde componentarray weergegeven op sjabloon HTML in Angular2

We kunnen een dynamische component maken en de instanties van een component in een array opnemen en uiteindelijk op een sjabloon weergeven.

We kunnen bijvoorbeeld twee widgetcomponenten overwegen, ChartWidget en PatientWidget die de klasse WidgetComponent hebben uitgebreid die ik in de container wilde toevoegen.

ChartWidget.ts

@Component({
selector: 'chart-widget',
templateUrl: 'chart-widget.component.html',
providers: [{provide: WidgetComponent, useExisting: forwardRef(() => ChartWidget) }]
})

export class ChartWidget extends WidgetComponent implements OnInit {
       constructor(ngEl: ElementRef, renderer: Renderer) {
    super(ngEl, renderer);
    }
    ngOnInit() {}
     close(){
      console.log('close');
    }
    refresh(){
      console.log('refresh');
    }
    ...
}

chart-widget.compoment.html (met behulp van primeng Panel)

<p-panel [style]="{'margin-bottom':'20px'}">
    <p-header>
        <div class="ui-helper-clearfix">
           <span class="ui-panel-title" style="font-size:14px;display:inline-block;margin-top:2px">Chart Widget</span>
            <div class="ui-toolbar-group-right">                
               <button pButton type="button" icon="fa-window-minimize" (click)="minimize()"</button>
              <button pButton type="button" icon="fa-refresh" (click)="refresh()"></button>
              <button pButton type="button"  icon="fa-expand" (click)="expand()" ></button>
             <button pButton type="button" (click)="close()" icon="fa-window-close"></button>
                    </div>
                </div>
    </p-header>
      some data
</p-panel>

DataWidget.ts

@Component({
    selector: 'data-widget',
    templateUrl: 'data-widget.component.html',
    providers: [{provide: WidgetComponent, useExisting: forwardRef(() =>DataWidget) }]
    })

export class DataWidget extends WidgetComponent implements OnInit {
       constructor(ngEl: ElementRef, renderer: Renderer) {
    super(ngEl, renderer);
    }
    ngOnInit() {}
    close(){
      console.log('close');
    }
    refresh(){
      console.log('refresh');
    }
    ...
}

data-widget.compoment.html (hetzelfde als chart-widget met primeng Panel)

WidgetComponent.ts

@Component({
  selector: 'widget',
  template: '<ng-content></ng-content>'
})
export  class WidgetComponent{
}

we kunnen dynamische componentinstanties maken door de bestaande componenten te selecteren. Bijvoorbeeld,

@Component({

    selector: 'dynamic-component',
    template: `<div #container><ng-content></ng-content></div>`

})
export class DynamicComponent {
@ViewChild('container', {read: ViewContainerRef}) container: ViewContainerRef; 

    public addComponent(ngItem: Type<WidgetComponent>): WidgetComponent {
    let factory = this.compFactoryResolver.resolveComponentFactory(ngItem);
    const ref = this.container.createComponent(factory);
    const newItem: WidgetComponent = ref.instance;              
    this._elements.push(newItem);                 
    return newItem;
  }
}

Eindelijk gebruiken we het in app-component. app.component.ts

@Component({
  selector: 'app-root',
  templateUrl: './app/app.component.html',
  styleUrls: ['./app/app.component.css'],
  entryComponents: [ChartWidget,  DataWidget], 
})

export class AppComponent {
   private elements: Array<WidgetComponent>=[];
   private WidgetClasses = {
      'ChartWidget': ChartWidget,
      'DataWidget': DataWidget        
  }
  @ViewChild(DynamicComponent) dynamicComponent:DynamicComponent;  
  
   addComponent(widget: string ): void{                         
     let ref= this.dynamicComponent.addComponent(this.WidgetClasses[widget]);    
     this.elements.push(ref); 
     console.log(this.elements);
  
     this.dynamicComponent.resetContainer();                     
  }
}

app.component.html

<button (click)="addComponent('ChartWidget')">Add ChartWidget</button>
<button (click)="addComponent('DataWidget')">Add DataWidget</button>

<dynamic-component [hidden]="true" ></dynamic-component>  

<hr>
Dynamic Components
<hr>
<widget *ngFor="let item of elements">
    <div>{{item}}</div>
   <div [innerHTML]="item._ngEl.nativeElement.innerHTML | sanitizeHtml">
   </div>
</widget>

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

Sommige aanpassing door @yurzui om muisgebeurtenis op de widgets te gebruiken

view.directive.ts

import {ViewRef, Directive, Input, ViewContainerRef} uit '@ angular / core';

@Directive({
    selector: '[view]'
})
export class ViewDirective {
  constructor(private vcRef: ViewContainerRef) {}

  @Input()
  set view(view: ViewRef) {
    this.vcRef.clear();
    this.vcRef.insert(view);
  }

  ngOnDestroy() {
    this.vcRef.clear()
  }
}

app.component.ts

private elements: Array<{ view: ViewRef, component: WidgetComponent}> = [];

...
addComponent(widget: string ): void{
  let component = this.dynamicComponent.addComponent(this.WidgetClasses[widget]);
  let view: ViewRef = this.dynamicComponent.container.detach(0);
  this.elements.push({view,component});

  this.dynamicComponent.resetContainer();
}

app.component.html

<widget *ngFor="let item of elements">
  <ng-container *view="item.view"></ng-container>
</widget>

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



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow