Angular2中的ViewChildren Decorator可以与Interfaces一起使用吗?

时间:2016-03-29 14:14:54

标签: angular angular2-directives

我理解Angular 2的方式,ViewChildren装饰器允许Component获取其他组件或指令的查询。当我知道组件的特定类型时,我可以在Typescript中使用它,但是当我只知道组件的接口时,我希望能够获得QueryList。这样,我可以遍历视图组件。

例如,在组件中我可能有这个:

@ViewChildren(Box) shapes: QueryList<Box>;

其中Box是具体的TypeScript类。我想拥有的是:

@ViewChildren(IShape) shapes: QueryList<IShape>;

其中IShape是Boxes或其他组件可能实现的接口。这样,视图可以非常动态,我的代码仍然可以工作。有没有推荐的方法来处理这个问题?

2 个答案:

答案 0 :(得分:3)

实际上有一种方法可以做一些像你想要做的事情,虽然可能不是使用Typescript接口,因为GünterZöchbauer是正确的,一旦代码被转换为javascript它们就不存在。

但是,您可以使用父类。父级可能是一个抽象类。现在我考虑一下,接口应该也可以工作,如果它们被转换成运行时命名空间,我不知道它们是不是。

@Component({
  selector: 'square',
  providers: [provide(Shape, useExisting: forwardRef( ()=>Square )]
})
class Square extends Shape {}

请参阅此讨论。

https://github.com/angular/angular/issues/8580

现在我想在下面留下我自己的例子给那些像我这样使用es5的人,并且为了更全面的用例演示。我试图平衡额外细节的数量,使得这个例子整体上有意义,而不会产生无关紧要的东西。

如果您打算投票让我离开主题,请停止阅读。

我需要在仪表板组件中执行一些自定义调整大小逻辑,并且我希望只有在父仪表板组件中执行自定义调整大小逻辑后才能重新呈现几种不同类型的图表指令。我的一些图表实际上是组件,它没有引起任何问题。在es5中使以下模式工作所需的任何其他内容都是标准的。您不需要在为NgModule提供的提供程序列表中包含app.Renderable。

renderable.class.js

(function(app) {
    app.Renderable = ng.core.Class({
        constructor : [function Renderable() {}],
        render : function() {}
    });
})(window.app || (window.app = {}));

图表-one.directive.js

(function(app) {
    app.ChartOneDirective = ng.core.Directive({
        selector : 'canvas[chart-one]',
        inputs : ['config:chart-one'],
        providers : [{
            provide: app.Renderable, 
            useExisting: ng.core.forwardRef(function(){
                return app.ChartOneDirective;
            }),
        }]
    }).Class({
        extends : app.Renderable,
        constructor : [/* injections */ function ChartOneDirective(/* injections */) {
            // do stuff
        }],

        // other methods

        render : function() {
            // render the chart
        }
    });
})(window.app || (window.app = {}));

图表-two.directive.js

(function(app) {
    app.ChartTwoDirective = ng.core.Directive({
        selector : 'canvas[chart-two]',
        inputs : ['config:chart-two'],
        providers : [{
            provide: app.Renderable, 
            useExisting: ng.core.forwardRef(function(){
                return app.ChartTwoDirective;
            }),
        }]
    }).Class({
        extends : app.Renderable,
        constructor : [/* injections */ function ChartTwoDirective(/* injections */) {
            // do stuff
        }],

        // other methods

        render : function() {
            // render the chart
        }
    });
})(window.app || (window.app = {}));

dashboard.component.js

(function(app) {
    app.DashboardComponent = ng.core.Component({
        selector : 'dashboard-component',
        templateUrl : 'components/dashboard/dashboard.component.html',
        host : {
            '(window.resize)' : 'rerender()',
        },
        queries : {
            renderables : new ng.core.ViewChildren(app.Renderable),
            // other view children for resizing purposes
        }
    }).Class({
        constructor : [/* injections */ function DashboardComponent(/* injections */) {
            // do stuff
        }],

        resize : function() {
            // do custom sizing of things within the dom
        },

        // other methods

        rerender : function() {
            this.resize();
            this.renderables.forEach(function(r){
                r.render();
            });
        }
    });
})(window.app || (window.app = {}));

dashboard.component.html

<div #sizeMe>
    <div class='canvas-wrapper'><canvas [chart-one]></canvas></div>
    <div class='canvas-wrapper'><canvas [chart-two]></canvas></div>
    <div class='canvas-wrapper'><canvas [chart-one]></canvas></div>

    <div #sizeMeToo>
        <div class='canvas-wrapper'><canvas [chart-two]></canvas></div>
        <div class='canvas-wrapper'><canvas [chart-one]></canvas></div>
    </div>
</div>

现在,在es5 javascript中,实际上没有必要扩展Renderable类以使其工作。此外,您可以在提供程序列表中放置多个提供程序,从而允许查询我的多个标记的组件或指令。因此,你可以说你可以“实现”几个“接口”,用于ViewChild选择的目的,在经典的javascript方式中没有任何实际保证。

答案 1 :(得分:2)

不,接口信息在运行时不存在,因此不能用于查询实现特定接口的不同组件。

支持只有一种类型或模板变量列表,如

@ViewChildren('a,b,c,d') children;

<div #a>a</div>
<div #b>a</div>
<div #c>a</div>

<div #d>a</div>
<div #d>a</div>

<div #e>a</div>

会在children

中产生5个引用