Может ли декоратор ViewChildren в Angular2 работать с интерфейсами?

Насколько я понимаю Angular 2, декоратор ViewChildren позволяет компоненту получить запрос для других компонентов или директив. Я могу заставить это работать в Typescript, когда я знаю конкретный тип компонента, но я хотел бы иметь возможность получить QueryList, когда я просто знаю интерфейс компонента. Таким образом, я могу перебирать компоненты представления.

Например, в компоненте у меня может быть это:

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

где Box — это конкретный класс TypeScript. Я хотел бы иметь это:

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

где IShape — это интерфейс, который могут реализовать блоки или другие компоненты. Таким образом, представление может быть очень динамичным, и мой код все равно будет работать. Есть ли рекомендуемый способ справиться с этим?


person brianv    schedule 29.03.2016    source источник
comment
Должна быть возможность запрашивать общие суперклассы github.com/angular/angular. /issues/8580#issuecomment-218525425   -  person Günter Zöchbauer    schedule 11.05.2016


Ответы (2)


На самом деле есть способ сделать что-то похожее на то, что вы пытаетесь сделать, хотя, возможно, и не с интерфейсами Typescript, поскольку Гюнтер Цохбауэр прав в том, что они не существуют как таковые после переноса кода в javascript.

Однако вы можете использовать родительский класс. Родитель, вероятно, может быть абстрактным классом. Теперь, когда я думаю об этом, интерфейсы тоже должны работать, ЕСЛИ они перенесены в пространство имен времени выполнения, что я не знаю, так ли это.

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

Обратитесь к этому обсуждению.

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

Теперь я хочу оставить свой собственный пример ниже для тех, кто использует es5, как я, и ради более тщательной демонстрации вариантов использования. Я попытался сбалансировать количество дополнительных деталей таким образом, чтобы пример имел смысл в целом, не становясь лишним.

ПОЖАЛУЙСТА, если вы собираетесь проголосовать против меня за отклонение от темы, просто перестаньте читать здесь.

Мне нужно было выполнить некоторую пользовательскую логику изменения размера в компоненте информационной панели, и я хотел, чтобы несколько различных типов директив диаграммы перерисовывались только после того, как я выполнил свою пользовательскую логику изменения размера в родительском компоненте информационной панели. Некоторые из моих диаграмм на самом деле были компонентами, и это не вызывало проблем. Все остальное, что вам нужно, чтобы следующий шаблон работал в es5, является стандартным. Вам не нужно включать app.Renderable в список поставщиков, предоставленных вашему NgModule.

визуализируемый.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 = {}));

панель инструментов.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 = {}));

панель инструментов.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>

Теперь, в javascript es5, фактически нет необходимости расширять класс Renderable, чтобы это работало. Кроме того, вы можете поместить более одного провайдера в свой список провайдеров и, таким образом, разрешить запрашивать ваш компонент или директиву для моих нескольких токенов. Таким образом, вы можете сказать, что можете «реализовать» несколько «интерфейсов» для целей выбора ViewChild в классическом стиле javascript, на самом деле ничего не гарантировано.

person Kyle Zimmer    schedule 14.12.2016

Нет, информация об интерфейсе не существует во время выполнения и поэтому не может использоваться для запроса различных компонентов, реализующих определенный интерфейс.

Поддерживается только один тип или список переменных шаблона, например

@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>

приведет к 5 ссылкам в children

person Günter Zöchbauer    schedule 29.03.2016