Я хотел бы создать расширения для некоторых компонентов, уже развернутых в Angular 2, без необходимости переписывать их почти полностью, поскольку базовый компонент может претерпеть изменения, и хотелось бы, чтобы эти изменения также были отражены в его производных компонентах.
Я создал этот простой пример, чтобы попытаться лучше объяснить мои вопросы:
Со следующим базовым компонентом app/base-panel.component.ts
:
import {Component, Input} from 'angular2/core';
@Component({
selector: 'base-panel',
template: '<div class="panel" [style.background-color]="color" (click)="onClick($event)">{{content}}</div>',
styles: [`
.panel{
padding: 50px;
}
`]
})
export class BasePanelComponent {
@Input() content: string;
color: string = "red";
onClick(event){
console.log("Click color: " + this.color);
}
}
Хотите ли вы создать другой производный компонент, изменив только, например, поведение основного компонента в случае цвета примера app/my-panel.component.ts
:
import {Component} from 'angular2/core';
import {BasePanelComponent} from './base-panel.component'
@Component({
selector: 'my-panel',
template: '<div class="panel" [style.background-color]="color" (click)="onClick($event)">{{content}}</div>',
styles: [`
.panel{
padding: 50px;
}
`]
})
export class MyPanelComponent extends BasePanelComponent{
constructor() {
super();
this.color = "blue";
}
}
Полный рабочий пример в Plunker
Примечание: очевидно, этот пример прост и может быть решен, иначе нет необходимости использовать наследование, но он предназначен только для иллюстрации реальной проблемы.
Как вы можете видеть в реализации производного компонента app/my-panel.component.ts
, большая часть реализации была повторена, и единственная часть, которая действительно была унаследована, была class
BasePanelComponent
, но @Component
должна была быть полностью повторена, а не только измененные части, как selector: 'my-panel'
.
Есть ли какой-нибудь способ сделать буквально полное наследование компонента Angular2, унаследовав, например, class
определение разметки / аннотации @Component
?
Редактировать 1 - Запрос функции
В проект на GitHub добавлен запрос на добавление angular2: аннотации компонентов Extend / Inherit angular2 # 7968
Редактировать 2 - Закрытый запрос
Запрос был закрыт, по этой причине , что в течение короткого времени не будет известно, как объединить декоратор будет сделано. Оставив нас без вариантов. Поэтому мое мнение цитируется в выпуске .
источник
Ответы:
Альтернативное решение:
Этот ответ Тьерри Темплиера - альтернативный способ обойти проблему.
После некоторых вопросов с Тьерри Темплиером я пришел к следующему рабочему примеру, который соответствует моим ожиданиям в качестве альтернативы ограничения наследования, упомянутого в этом вопросе:
1 - Создать собственный декоратор:
2 - Базовый компонент с декоратором @Component:
3 - Подкомпонент с декоратором @CustomComponent:
Плункр с полным примером.
источник
Angular 2 версия 2.3 была только что выпущена, и она включает в себя нативное наследование компонентов. Похоже, вы можете наследовать и переопределять все, что вы хотите, за исключением шаблонов и стилей. Некоторые ссылки:
Новые функции в Angular 2.3
Наследование компонентов в Angular 2
Plunkr демонстрирует наследование компонентов
источник
More than one component matched on this element
если вы этого не сделаете.@Component()
теге. Но вы можете поделиться .html или .css, ссылаясь на тот же файл, если хотите. В общем, это большой плюс.Теперь, когда TypeScript 2.2 поддерживает Mixins с помощью выражений Class, у нас есть намного лучший способ выразить Mixins на компонентах. Помните, что вы также можете использовать наследование компонентов начиная с версии 2.3 ( обсуждение ) или пользовательский декоратор, как обсуждалось в других ответах здесь. Тем не менее, я думаю, что у Mixins есть некоторые свойства, которые делают их предпочтительными для повторного использования в компонентах:
Я настоятельно рекомендую вам прочитать объявление TypeScript 2.2 выше, чтобы понять, как работают Mixins. Связанные обсуждения в угловых проблемах GitHub предоставляют дополнительные детали.
Вам понадобятся эти типы:
И затем вы можете объявить Mixin как этот
Destroyable
mixin, который помогает компонентам отслеживать подписки, которые должны быть расположены вngOnDestroy
:Чтобы смешать
Destroyable
вComponent
, вы объявляете свой компонент следующим образом:Обратите внимание, что
MixinRoot
это необходимо только тогда, когда вы хотите, чтобыextend
Mixin композиции. Вы можете легко расширить несколько миксинов, напримерA extends B(C(D))
. Это очевидная линеаризация миксинов, о которой я говорил выше, например, вы эффективно составляете иерархию наследованияA -> B -> C -> D
.В других случаях, например, когда вы хотите создать Mixins для существующего класса, вы можете применить Mixin следующим образом:
Тем не менее, я обнаружил, что первый способ работает лучше всего,
Components
иDirectives
, так как они также должны быть украшены@Component
или в@Directive
любом случае.источник
function Destroyable<T extends Constructor<{}>>(Base = class { } as T)
. Таким образом, я могу создавать миксины, используяextends Destroyable()
.Обновить
Наследование компонентов поддерживается начиная с 2.3.0-rc.0
оригинал
До сих пор самым удобным для меня , чтобы сохранить шаблон & стили в отдельный
*html
и*.css
файлы и указать те , черезtemplateUrl
иstyleUrls
, поэтому его легко использовать повторно.источник
@Input()
и@Output()
декораторы, не так ли?Насколько я знаю, наследование компонентов еще не было реализовано в Angular 2, и я не уверен, есть ли у них планы, однако, поскольку Angular 2 использует машинопись (если вы решили пойти по этому пути), вы можете использовать наследование классов. делая
class MyClass extends OtherClass { ... }
. Для наследования компонентов я бы предложил принять участие в проекте Angular 2, перейдя по адресу https://github.com/angular/angular/issues и отправив запрос на добавление функции!источник
export class MyPanelComponent extends BasePanelComponent
), проблема заключается только в том, что аннотации / декораторы не наследуются.@SubComponent()
), который помечает класс как подкомпонент, или иметь дополнительное поле в@Component
декораторе, которое позволяет вам ссылаться на родительский компонент для наследования.Давайте разберемся с некоторыми ключевыми ограничениями и возможностями системы наследования компонентов Angular.
Компонент наследует только логику класса:
Эти функции очень важно иметь в виду, поэтому давайте рассмотрим каждую из них независимо.
Компонент наследует только логику класса
Когда вы наследуете Компонент, вся логика внутри одинаково наследуется. Стоит отметить, что только открытые члены наследуются, поскольку частные члены доступны только в классе, который их реализует.
Все метаданные в декораторе @Component не наследуются
Тот факт, что метаданные не наследуются, на первый взгляд может показаться нелогичным, но, если подумать, это действительно имеет смысл. Если вы наследуете от компонента Component (componentA), вы бы не хотели, чтобы селектор ComponentA, от которого вы наследуете, заменил селектор ComponentB, который является классом, который наследует. То же самое можно сказать и о template / templateUrl, а также о style / styleUrls.
Свойства компонента @Input и @Output наследуются
Это еще одна особенность, которая мне очень нравится в компоненте Inheritance в Angular. В простом предложении, когда у вас есть пользовательские свойства @Input и @Output, эти свойства наследуются.
Жизненный цикл компонента не наследуется
Эта часть не так очевидна, особенно для людей, которые не очень активно работали с принципами ООП. Например, скажем, у вас есть ComponentA, которая реализует одну из многих ловушек Angular, таких как OnInit. Если вы создадите ComponentB и унаследуете ComponentA, жизненный цикл OnInit из ComponentA не сработает, пока вы не вызовете его явно, даже если у вас есть этот жизненный цикл OnInit для ComponentB.
Вызов методов Super / Base Component
Чтобы получить метод ngOnInit () из огня ComponentA, нам нужно использовать ключевое слово super, а затем вызвать нужный нам метод, в данном случае ngOnInit. Ключевое слово super ссылается на экземпляр компонента, который наследуется, от которого в этом случае будет ComponentA.
источник
Если вы читаете библиотеки CDK и библиотеки материалов, они используют наследование, но не столько для самих компонентов, но и для контент-проекции - главное ИМО. см. эту ссылку https://blog.angular-university.io/angular-ng-content/, где написано «ключевая проблема с этим дизайном»
Я знаю, что это не отвечает на ваш вопрос, но я действительно считаю, что следует избегать наследования / расширения компонентов . Вот мои рассуждения:
Если абстрактный класс, расширенный двумя или более компонентами, содержит совместно используемую логику: используйте сервис или даже создайте новый класс машинописи, который может совместно использоваться двумя компонентами.
Если абстрактный класс ... содержит общие переменные или функции onClicketc, то в html двух расширенных представлений компонентов будет дублирование. Это плохая практика, и общий HTML должен быть разбит на компоненты. Эти Компонент (ы) могут быть разделены между двумя компонентами.
Я пропускаю другие причины наличия абстрактного класса для компонентов?
Примером, который я видел недавно, были компоненты, расширяющие AutoUnsubscribe:
это было основанием, потому что во всей большой кодовой базе
infiniteSubscriptions.push()
использовалось только 10 раз. Кроме импорта и расширение наAutoUnsubscribe
самом деле занимает больше кода , чем просто добавлениеmySubscription.unsubscribe()
вngOnDestroy()
методе самого компонента, который требует дополнительной логики в любом случае.источник
Если кто-то ищет обновленное решение, ответ Фернандо в значительной степени идеален. За исключением того, что
ComponentMetadata
было объявлено устаревшим. ИспользованиеComponent
вместо этого работало для меня.Полный
CustomDecorator.ts
файл Custom Decorator выглядит следующим образом:Затем импортируйте его в новый
sub-component.component.ts
файл компонента и используйте@CustomComponent
вместо@Component
этого:источник
Вы можете наследовать @Input, @Output, @ViewChild и т. Д. Посмотрите на пример:
источник
Компоненты могут быть расширены так же, как наследование классов машинописного текста, просто вы должны переопределить селектор новым именем. Все свойства Input () и Output () из родительского компонента работают как обычно
Обновить
@Component это декоратор,
Декораторы применяются при объявлении класса не на объектах.
По сути, декораторы добавляют некоторые метаданные к объекту класса, и к ним нельзя получить доступ посредством наследования.
Если вы хотите получить наследство декоратора, я бы предложил написать собственный декоратор. Нечто вроде нижеприведенного примера.
См. Https://medium.com/@ttemplier/angular2-decorators-and-class-inheritance-905921dbd1b7.
источник
источник