Angular2中的ViewChildren装饰器可以与Interfaces一起使用吗?

bri*_*anv 5 angular2-directives angular

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

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

@ViewChildren(Box) shapes: QueryList<Box>;
Run Code Online (Sandbox Code Playgroud)

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

@ViewChildren(IShape) shapes: QueryList<IShape>;
Run Code Online (Sandbox Code Playgroud)

IShapeBox或其他组件可以实现的接口在哪里。这样,视图可以非常动态,并且我的代码仍然可以工作。有没有建议的方法来解决这个问题?

Gün*_*uer 5

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

仅支持单一类型或模板变量列表,例如

@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>
Run Code Online (Sandbox Code Playgroud)

将产生 5 条参考文献children


Kyl*_*mer 5

实际上,有一种方法可以执行您尝试执行的操作,尽管可能不使用Typescript接口,因为GünterZöchbauer正确地认为,一旦将代码转换为javascript,它们就不会存在。

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

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

请参阅此讨论。

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 = {}));
Run Code Online (Sandbox Code Playgroud)

chart-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 = {}));
Run Code Online (Sandbox Code Playgroud)

chart-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 = {}));
Run Code Online (Sandbox Code Playgroud)

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 = {}));
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

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