2016-04-15 104 views
1

虽然这个话题已经在其他职位这样的讨论:打字稿及角反射2

Dynamically loading a typescript class (reflection for typescript)

我无法找到一个答案,我的具体问题。所以,如果这是重复的,请原谅我。

我想在Angular 2(使用Typescript)中创建一个非常简单的指令,它允许动态添加或删除一组由Type代表的控件。例如,如果类型是:

class Stone{ 
    constructor(
    public nameOfStone?: string, 
    public typeOfStone?: string 
){} 
} 

的UI将有这样的事情:

Screenshot 1

我能够获得与特定类型(例如:石)这方面的工作。但是,鉴于指令的目的只是添加这个动态添加/删除功能,我觉得参数化要创建的类型并将其用于不同的类型定义是有意义的。我试图在Component类是这样的:

import {Component} from 'angular2/core'; 
import {NgForm} from 'angular2/common'; 
import {ControlGroup, Control, FormBuilder, FORM_DIRECTIVES} from 'angular2/common' 
@Component({ 
    selector: 'stone-details', 
    templateUrl: '../stones/stone-details.component.html', 
    directives: [FORM_DIRECTIVES] 
}) 
export class StoneComponent { 
    type = 'Stone'; 
    Stones = new Array<Stone>(); 

    addBtnClicked(){ 
    let Stone = Object.create(window['Stone'].prototype); 
    //let Stone = new Stone('', ''); 
    this.Stones.push(Stone); 
    } 
    removeBtnClicked(index: number){ 
    if(index >= this.Stones.length){ 
     alert('Not a valid index'); 
    }else if(confirm('Remove this Stone?')){ 
     this.Stones.splice(index, 1); 
    } 
    } 
} 

class Stone{ 
    constructor(
    public nameOfDeity?: string, 
    public typeOfDeity?: string 
){} 
} 

当我使用注释行 let Stone = new Stone('', ''); 部件完美地工作,但如果我用 let Stone = Object.create(window['Stone'].prototype); 它似乎并没有工作,我看到的错误是 angular2.dev.js:23941 ORIGINAL EXCEPTION: TypeError: Cannot read property 'prototype' of undefined

我最初认为导出Stone类会有帮助,但没有一个疯狂的变体(导出类,试图将该类引用为window ['StoneComponent'] .portal_1 ['Stone'])帮助。我知道该组件并不直接在窗口组件下可见,但我不确定我错过了什么。有没有其他方法可以做到这一点?我错过了什么吗?请指教。

P.S:我正在使用Angular 2和Typescript的最新版本(几天前我开始使用这个应用程序)。

+0

'Object.create(Stone.prototype)'不工作? – jpopesculian

+0

它的确如此,但我无法让它变成动态的。也就是说,Object.create(Stone.prototype)的作品,与Stone = new Stone()并没有多大区别。但是我无法使用变量代替Stone类型,例如:Object.create( .prototype) – user1452030

+0

这很困难,因为它很难知道父对象是什么。我猜不是它的窗户。你尝试过'这个'吗?否则,您可以创建自己的可能的原型字典,然后通过该字典访问原型(似乎足够安全,您只需要维护它)。否则,可以尝试'eval(“Stone”)'?虽然 – jpopesculian

回答

0

由于班级功能简单,您可以使用new func()创建实例,但您仍然必须从外部代码传递func

我想最有效的解决方案是:只要对象具有相同的属性集

export class StoneComponent<T> { 
    addBtnClicked(){ 
    let item:T = <T>{} 
    this.items.push(item); 
    } 
} 

类型匹配。

1

您的代码的问题是定义顺序。

具体而言,类定义是而不是这样悬挂的函数的定义是。棘手的部分是类型Stone是悬挂,这是完全有效的,但 Stone,构造函数,不是。

为了解决这个问题,只需在组件上方定义Stone或将其提取到单独的模块中并导入它。

不要尝试将其推到一个全局变量,说window。这是一个非常糟糕的做法,会比人们想象的更快地导致错误和名称冲突。它也挫败了模块的好处。

总之,你需要的是

class Stone { 
    constructor(
    readonly nameOfDeity?: string, 
    readonly typeOfDeity?: string 
) {} 
} 

export class StoneComponent { 
    kind = 'Stone'; 
    stones: Stone[] = []; 

    addBtnClicked() { 
    const stone = new Stone(); 
    this.stones.push(stone); 
    } 
    removeBtnClicked(index: number) { 
    if (index >= this.stones.length) { 
     alert('Not a valid index'); 
    } else if (confirm('Remove this Stone?')){ 
     this.stones.splice(index, 1); 
    } 
    } 
} 

UPDATE 因为在你的国家,这将是一个通用组件,你将不得不在实际的类是通过选择多个类原题kind组件类的属性。您可能需要考虑以下模式。

组件现场kinds.ts

export class Stone { ... } 

export class Widget { ... } 

export class Gizmo { ... } 

仿制component.ts

import * as kinds from './component-field-kinds'; 

type Kind = keyof typeof kinds; 

export class GenericComponent { 
    @Input() kind: Kind; 

    values: typeof kinds[Kind][] = []; 

    addBtnClicked() { 
    const value = new kinds[this.kind](); 
    this.values.push(value); 
} 

注意,有什么值得注意的是,JavaScript的,因此打字稿没有这样的作为一个动态类加载器的东西。这就是语言始终如一地工作,整个结构都是一流的。

这不是Java。