Angular_2

Angular 2 IntroductionAhead-of-time (AOT) compilation with Angular 2Angular - ForLoopAngular 2 - ProtractorAngular 2 Advanced Component ExamplesAngular 2 Angular-cliAngular 2 angular-cli test coverageAngular 2 Angular2 AnimationsAngular 2 Angular2 CanActivateAngular 2 Angular2 Custom ValidationsAngular 2 Angular2 DatabindingAngular 2 Angular2 in Memory Web APIAngular 2 Angular2 Input() output()Angular 2 Angular2 provide external data to App before bootstrapAngular 2 Angular2 using webpackAngular 2 AnimationAngular 2 Attribute directives to affect the value of properties on the host node by using the @HostBinding decorator.Angular 2 BarrelAngular 2 Brute Force UpgradingAngular 2 Bypassing Sanitizing for trusted valuesAngular 2 Change detection and manual triggeringAngular 2 Commonly built-in directives and servicesAngular 2 Component interactionsAngular 2 ComponentsAngular 2 CRUD in Angular2 with Restful APIAngular 2 custom ngx-bootstrap datepicker + inputAngular 2 Data Driven FormsAngular 2 Debugging Angular2 typescript application using Visual Studio CodeAngular 2 Detecting resize eventsAngular 2 DirectivesAngular 2 Directives & components : @Input @OutputAngular 2 Dropzone in Angular2Angular 2 Dynamically add components using ViewContainerRef.createComponentAngular 2 EventEmitter ServiceAngular 2 Example for routes such as /route/subroute for static urlsAngular 2 Feature ModulesAngular 2 Forms UpdateAngular 2 How to use ngforAngular 2 How to Use ngifAngular 2 HTTP InterceptorAngular 2 Installing 3rd party plugins with angular-cli@1.0.0-beta.10Angular 2 Lazy loading a moduleAngular 2 Lifecycle HooksAngular 2 Mocking @ngrx/StoreAngular 2 ModulesAngular 2 NgRxAngular 2 Optimizing rendering using ChangeDetectionStrategyAngular 2 OrderBy PipeAngular 2 Page titleAngular 2 PipesAngular 2 RoutingAngular 2 Routing (3.0.0+)Angular 2 Service WorkerAngular 2 Services and Dependency InjectionAngular 2 TemplatesAngular 2 Testing ngModelAngular 2 unit testingAngular 2 Update typingsAngular 2 Zone.jsAngular material designAngular reduxAngular RxJS Subjects and Observables with API requestsBootstrap Empty module in angular 2Configuring ASP.NET Core application to work with Angular 2 and TypeScriptCreate an Angular 2+ npm packageCreating an Angular npm libraryTesting an Angular 2 AppUse native webcomponents in Angular 2Using third party libraries like jQuery in Angular 2



Angular 2 Dynamically add components using ViewContainerRef.createComponent

From WikiOD

A wrapper component that adds dynamic components declaratively[edit | edit source]

A custom component that takes the type of a component as input and creates an instance of that component type inside itself. When the input is updated, the previously added dynamic component is removed and the new one added instead.

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

This allows you to create dynamic components like

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

Plunker example

Dynamically add component on specific event(click)[edit | edit source]

Main Component File:

//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 example

Rendered dynamically created component array on template html in Angular2[edit | edit source]

We can create dynamic component and get the instances of component into an array and finally rendered it on template.

For example, we can can consider two widget component, ChartWidget and PatientWidget which extended the class WidgetComponent that I wanted to add in the container.

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 (using 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 (same as chart-widget using primeng Panel)

WidgetComponent.ts

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

we can creat dynamic component instances by selecting the pre-existing components. For example,

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

Finally we use it 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

Some modification by @yurzui to use mouse event on the widgets

view.directive.ts

import { ViewRef, Directive, Input, ViewContainerRef } from '@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

Credit:Stack_Overflow_Documentation