Angular    Dynamic Component     ComponentFactoryResolver   
▌Introduction
In this article, we will continue learning ComponentFactoryResolver and create a dynamic-component-loader directive (or called “component-outlet”).
The
component-outlet will have the ability to load any (but one) component at
run-time and hence we can have much advanced usage and fun(?) with it J
▋Related articles 
▌Environment
▋Angular 2.1.0
▌Implement
Our
goal is to show customers’ data in LIST style or CARD style, which depends on
the choosing of the user. We will make use of the Component-Outlet to show the
different styles.
LIST
CARD
▋Component Outlet
| 
import { Directive,
  Component, ComponentFactory, OnChanges, Input, ViewContainerRef, Compiler,
  ComponentFactoryResolver } from '@angular/core'; 
@Directive({ 
    selector: '[component-outlet]' 
}) 
export class ComponentOutlet implements OnChanges { 
    @Input() selector: string; 
    componentRef; 
    constructor( 
        private vcRef: ViewContainerRef, 
        private resolver: ComponentFactoryResolver) { 
        } 
    ngOnChanges()
  { 
        if (!this.selector) return; 
        const factories =
  Array.from(this.resolver['_factories'].values()); 
        const factory: any =
  factories.find((x: any) => x.selector === this.selector); 
        const compRef:any = this.vcRef.createComponent(factory); 
        if (this.componentRef) { 
            this.componentRef.destroy(); 
        } 
        this.componentRef =
  compRef; 
    } 
    public ngOnDestroy() { 
        if (this.componentRef) { 
            this.componentRef.destroy(); 
            this.componentRef = null; 
        } 
    } 
} | 
PS.
OnChange will be fired while any
data-bound property of a directive/component changes. For more information, see
Lifecycle hooks.
▋Main component
Okay,
let’s put the directive on the main component and load customerdynamic-list component (or customerdynamic-card component) in constructor.
▋app.component.ts 
| 
import {Component, OnInit} from '@angular/core'; 
import {BrowserModule} from '@angular/platform-browser' 
@Component({ 
    selector: 'customermvc-index', 
    template: ` 
    <div class="form-group
  row" style="max-width:70%"> 
        <div class="col-sm-3"><button (click)="showLists()">Show Lists</button></div> 
        <div class="col-sm-3"><button (click)="showCards()">Show Cards</button></div> 
    </div> 
    <div> 
      <div component-outlet selector="{{component}}"></div> 
    </div> 
  `, 
}) 
export class
  CustomerDynamicIndexComponent implements OnInit { 
    private component: string; 
    constructor()
  { 
        this.component = "customerdynamic-list"; //or
  "customerdynamic-card" 
    } 
    private showLists() { 
        this.component = "customerdynamic-list"; 
} 
private showCards() { 
        this.component = "customerdynamic-card"; 
} 
} | 
PS. We can use property
binding on the Component-Outlet directive as well.
<div component-outlet [selector]="component"></div>
▋list.component.ts
I will ignore the html,
cus it’s not the key point here.
| 
import {Component, OnInit,
  Input} from '@angular/core'; 
import {Customer} from '../../../class/Customer'; 
import {CustomerService} from '../../../service/customer.service'; 
import {RestUriService} from '../../../service/resturi.service'; 
@Component({ 
    selector: 'customerdynamic-list', 
    providers:
  [CustomerService, RestUriService], 
    templateUrl: '/app/component/Basic/CustomerDynamic/list.component.html' 
}) 
export class
  CustomerDynamicListComponent implements OnInit { 
    customers:
  Customer[]; 
    constructor(private custService:
  CustomerService) { 
    } 
    ngOnInit() { 
        this.initCustomers(); 
    } 
    private initCustomers() { 
        this.custService.getAll().then( 
            data
  => { 
                this.customers = data 
            }); 
    } 
} | 
▋card.component.ts
The
card.component.ts is the same as list.component.ts except for their HTML.
▋Demo
▋Whaz next?
We will make
the Component-Oulet support passing parameter and inject to the dynamic
component for more flexible usage.
▌Github
 
▌Reference



 
沒有留言:
張貼留言