<!DOCTYPE html>
<html>
<head>
<base href="." />
<title>angular2 playground</title>
<link rel="stylesheet" href="style.css" />
<script src="https://unpkg.com/core-js@2.4.1/client/shim.min.js"></script>
<script src="https://unpkg.com/zone.js/dist/zone.js"></script>
<script src="https://unpkg.com/zone.js/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>
<script src="config.js"></script>
<script>
System.import('app')
.catch(console.error.bind(console));
</script>
</head>
<body>
<my-app>
loading...
</my-app>
</body>
</html>
/* Styles go here */
### Angular Starter Plunker - Typescript
System.config({
//use typescript for compilation
transpiler: 'typescript',
//typescript compiler options
typescriptOptions: {
emitDecoratorMetadata: true
},
paths: {
'npm:': 'https://unpkg.com/'
},
//map tells the System loader where to look for things
map: {
'app': './src',
'@angular/core': 'npm:@angular/core/bundles/core.umd.js',
'@angular/common': 'npm:@angular/common/bundles/common.umd.js',
'@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
'@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
'@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
'@angular/http': 'npm:@angular/http/bundles/http.umd.js',
'@angular/router': 'npm:@angular/router/bundles/router.umd.js',
'@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
'@angular/core/testing': 'npm:@angular/core/bundles/core-testing.umd.js',
'@angular/common/testing': 'npm:@angular/common/bundles/common-testing.umd.js',
'@angular/compiler/testing': 'npm:@angular/compiler/bundles/compiler-testing.umd.js',
'@angular/platform-browser/testing': 'npm:@angular/platform-browser/bundles/platform-browser-testing.umd.js',
'@angular/platform-browser-dynamic/testing': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js',
'@angular/http/testing': 'npm:@angular/http/bundles/http-testing.umd.js',
'@angular/router/testing': 'npm:@angular/router/bundles/router-testing.umd.js',
'rxjs': 'npm:rxjs',
'typescript': 'npm:typescript@2.0.2/lib/typescript.js'
},
//packages defines our app package
packages: {
app: {
main: './main.ts',
defaultExtension: 'ts'
},
rxjs: {
defaultExtension: 'js'
}
}
});
//main entry point
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {AppModule} from './app';
platformBrowserDynamic().bootstrapModule(AppModule)
//our root app component
import {Component, NgModule,ViewChild,
Type, OnInit } from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import {CommonModule} from "@angular/common";
import {ViewStack} from "./app/viewstack/ViewStack";
import {ChildA} from "./app/viewstack/child/ChildA";
import {ChildB} from "./app/viewstack/child/ChildB";
import {ChildC} from "./app/viewstack/child/ChildC";
@Component({
selector: 'my-app',
template: `
<button (click)="addChildA()">add childA</button>
<button (click)="addChildB()">add childB</button>
<button (click)="addChildC()">add childC</button>
<select (change)="onSelectChange($event)" [ngModel]="vsMain.selectedIndex" >
<option *ngFor="let view of children; let i = index;" [value]="i">{{i + ":" + view.constructor.name}}</option>
</select>
<button (click)="removeChild()" [disabled]="vsMain.selectedIndex < 0" >remove</button>
<view-stack #vsMain></view-stack>
`,
})
export class App {
@ViewChild('vsMain') private vsMain:ViewStack;
private children:any[] = [];
public constructor()
{
}
public ngOnInit():void {
this.addChildA();
this.addChildB();
this.addChildC();
}
private addChildA():void {
this.addChild(ChildA);
}
private addChildB():void {
this.addChild(ChildB);
}
private addChildC():void {
this.addChild(ChildC);
}
private addChild<T>(child:Type<T>):void {
this.vsMain.addChild(child);
this.children = this.vsMain.children;
this.vsMain.selectedIndex = this.vsMain.children.length - 1;
}
private onSelectChange($event:Event):void {
let selectedIndexStr:string = (<HTMLSelectElement>event.target).value;
this.vsMain.selectedIndex = +selectedIndexStr;
}
private removeChild():void {
this.vsMain.removeChildAt(this.vsMain.selectedIndex);
this.children = this.vsMain.children;
}
}
@NgModule({
declarations: [
App,
ViewStack,
ChildA,
ChildB,
ChildC
],
imports: [
BrowserModule,
FormsModule,
HttpModule,
CommonModule // ngClassとかつかうのに必要
],
bootstrap: [ App ],
// 動的に追加するコンポーネントはここに指定
entryComponents: [ChildA, ChildB, ChildC]
})
export class AppModule {}
import {
Component, ComponentFactory, ComponentFactoryResolver, ViewContainerRef, Type,
ComponentRef, ViewChild, AfterViewInit
} from "@angular/core";
@Component({
selector: 'view-stack',
providers: [],
template: `
<div #container>
</div>
`
})
export class ViewStack implements AfterViewInit {
private _children:ComponentRef<any>[] = [];
private _selectedIndex:number = -1;
@ViewChild('container', {read: ViewContainerRef}) private container:ViewContainerRef;
public constructor(
private _componentFactoryResolver: ComponentFactoryResolver
//, private _viewContainerRef: ViewContainerRef
)
{
}
public ngAfterViewInit():void {
//this._viewContainerRef.createEmbeddedView(this.container)
}
// interfaceか継承で縛ろうかとおもったけど、やめとく、、、
// public addChild<T extends IViewStackContainer>(childClass: Type<T>, index:number=-1):void {
public addChild<T>(childClass: Type<T>, index:number=-1):void {
let debug = this.container;
const componentFactory:ComponentFactory<T>
= this._componentFactoryResolver.resolveComponentFactory(childClass);
//const componentRef:ComponentRef<T> = this._viewContainerRef.createComponent(componentFactory);
const componentRef:ComponentRef<T> = this.container.createComponent(componentFactory);
if (index < 0) {
this._children.push(componentRef);
} else {
this._children.splice(index, 0, componentRef);
}
if (this._children.length === 1) { // 初回追加時
this._selectedIndex = 0;
this.showComponent(this._selectedIndex, -1);
} else {
componentRef.location.nativeElement.setAttribute("hidden", true);
}
}
private showComponent(showIndex:number, prevIndex:number):void {
if (showIndex === prevIndex){ // 同じ場合は何もしない ここにくることは無いはず
return;
}
if (0 <= prevIndex && prevIndex <= this._children.length - 1) {
this._children[prevIndex].location.nativeElement.setAttribute("hidden", true);
}
this._children[showIndex].location.nativeElement.removeAttribute("hidden");
}
public removeChild<T>(child:Type<T>):void {
for (let i=0; i<this._children.length; i++) {
if (this._children[i].instance === child) {
this.removeChildAt(i);
break;
}
}
}
public removeChildAt(index:number) {
this._children[index].destroy();
this._children.splice(index, 1);
if (this._children.length === 0) {
this._selectedIndex = -1;
return; // 表示するものが無くなったので何もしない
}
// 選択中の場合は削除されると後ろのやつが詰まってくるイメージなので
if (index === this._selectedIndex) {
if (index === this._children.length) { // 最後のやつ すでにspliceで減っているのでlength
this.showComponent(this._children.length - 1, -1); // 最後尾が削除されたので1個前を表示
this._selectedIndex = this._children.length - 1;
return;
}
this.showComponent(index, -1); // 最後尾では無かったので次のやつを表示
this._selectedIndex = index;
}
}
public set selectedIndex(index:number) {
this.showComponent(index, this._selectedIndex);
this._selectedIndex = index;
}
public get selectedIndex():number {
return this._selectedIndex;
}
public get selectedChild():any {
if (this._selectedIndex < 0) {
return null;
}
return this._children[this._selectedIndex].instance;
}
public get children():any[] {
let ret:any[] = [];
for (let i=0; i<this._children.length; i++) {
ret.push(this._children[i].instance);
}
return ret;
}
}
import { Component } from "@angular/core";
@Component({
selector: 'child-a',
providers: [],
template: `
<div>childA</div>
<label>only label</label>
`
})
export class ChildA {
}
import { Component } from "@angular/core";
@Component({
selector: 'child-b',
providers: [],
template: `
<div>childB</div>
<select>
<option *ngFor="let pref of prefs;" [value]="pref">{{pref}}</option>
</select>
`
})
export class ChildB {
private prefs:string[] = [
"東京都", "大阪府", "鹿児島県"
];
}
import { Component } from "@angular/core";
@Component({
selector: 'child-c',
providers: [],
template: `
<div>childC</div>
<input [(ngModel)]="inputValue">
`
})
export class ChildC {
private inputValue:string = "";
}