<!DOCTYPE html>
<html>
<head>
<base href="." />
<title>Angular2 動的コンポーネントのサンプル</title>
<!-- [ Load: Environment Library ] -->
<script src="https://unpkg.com/zone.js@0.7.2/dist/zone.js"></script>
<script src="https://unpkg.com/zone.js@0.7.2/dist/long-stack-trace-zone.js"></script>
<script src="https://unpkg.com/reflect-metadata@0.1.3/Reflect.js"></script>
<script src="https://unpkg.com/systemjs@0.19.31/dist/system.js"></script>
<!-- [ Load: Angular2 Library ] -->
<script>
System.config({
transpiler: 'typescript',
typescriptOptions: {
emitDecoratorMetadata: true,
skipLibCheck: true, // ライブラリのnull許容チェックをスキップ
strictNullChecks: true, // null許容チェックを有効
},
paths: {
// 'cdn'の定義
'cdn:': 'https://unpkg.com/',
},
map: {
'typescript': 'cdn:typescript@2.1.4',
'rxjs' : 'cdn:rxjs@5.0.1',
'@angular/core' : 'cdn:@angular/core@2.3.0',
'@angular/common' : 'cdn:@angular/common@2.3.0',
'@angular/compiler' : 'cdn:@angular/compiler@2.3.0',
'@angular/platform-browser' : 'cdn:@angular/platform-browser@2.3.0',
'@angular/platform-browser-dynamic': 'cdn:@angular/platform-browser-dynamic@2.3.0',
'@angular/http' : 'cdn:@angular/http@2.3.0',
'@angular/router' : 'cdn:@angular/router@3.3.0',
'@angular/forms' : 'cdn:@angular/forms@2.3.0',
},
packages: {
app: { defaultExtension: 'ts' },
rxjs: { defaultExtension: 'js' },
},
});
System.import('app/main.ts').catch(console.error.bind(console));
</script>
<style>
@import url(https://fonts.googleapis.com/css?family=Lato:400,700);
body{
font-family: Lato;
}
</style>
</head>
<body>
<my-app>loading...</my-app>
</body>
</html>
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { BrowserModule } from '@angular/platform-browser';
import {
Component,
ComponentFactoryResolver,
EventEmitter,
NgModule,
OnInit,
OnDestroy,
ViewContainerRef
} from '@angular/core';
import { Observable } from 'rxjs/Rx'; // MEMO: plunkerの場合は'rxjs/Rx'、ローカルでangular-cliの場合は'rxjs'
/**
* 動的に生成するサンプルコンポーネント
*/
@Component({
selector: 'app-sample',
template: `
<div style="margin: 1rem; padding: 1rem; border: 1px solid #eee;">
<button (click)="closeButton_Clicked()">CLOSE</button> No. {{_no}}
</div>
`,
})
export class SampleComponent implements OnInit, OnDestroy
{
/** クローズイベント */
private _closing = new EventEmitter<{}>();
/** コンポーネント生成元から受け取るパラメータ */
private _no: number = 0;
/** クローズイベントのgetプロパティ */
public get closing(): Observable<{}>
{
return this._closing;
}
/** コンポーネント生成元から受け取るパラメータのsetプロパティ */
public set no(value: number)
{
this._no = value;
}
/**
* Angular Lifecycle Hooks: OnInit
*/
public ngOnInit(): void
{
console.log(`SampleComponent.ngOnInit >> no="${this._no}"`);
}
/**
* Angular Lifecycle Hooks: OnDestroy
*/
public ngOnDestroy(): void
{
console.log(`SampleComponent.ngOnDestroy >> no="${this._no}"`);
}
/**
* CLOSEボタンのクリックイベントハンドラ
*/
private closeButton_Clicked(): void
{
// クローズイベントを発行
this._closing.emit({});
}
}
/**
* メインAppコンポーネント
*/
@Component({
selector: 'my-app',
template: `
<div style="padding: 1rem; border: 1px solid #eee;">
<h2>Angular2 Dynamic Component Sample</h2>
<button (click)="createButton_Clicked()">CREATE</button>
</div>
`,
})
export class App
{
public constructor(
private _componentFactoryResolver: ComponentFactoryResolver,
private _viewContainerRef: ViewContainerRef)
{
}
/**
* CREATEボタンのクリックイベントハンドラ
*/
private createButton_Clicked(): void
{
// コンポーネント生成器を初期化
const componentFactory = this._componentFactoryResolver.resolveComponentFactory(SampleComponent);
// 動的にコンポーネントを生成
const componentRef = this._viewContainerRef.createComponent(componentFactory);
// 動的に生成したコンポーネントにパラメータを渡す
componentRef.instance.no = Math.floor(Math.random() * 100); // 0~99のランダム値を渡す
// closingイベントを受けたらコンポーネント破棄する
componentRef.instance.closing.subscribe(() => {
componentRef.destroy();
});
}
}
/**
* アプリケーションモジュール
*/
@NgModule({
imports: [ BrowserModule ],
declarations: [ App, SampleComponent ], // 独自のcomponent/directiveをdeclarationsに指定する
bootstrap: [ App ],
entryComponents: [ SampleComponent ], // 動的に生成するcomponentをentryComponentsに指定する
})
export class AppModule
{
}
platformBrowserDynamic().bootstrapModule(AppModule);