Ich möchte Erweiterungen für einige Komponenten erstellen, die bereits in Angular 2 bereitgestellt wurden, ohne sie fast vollständig neu schreiben zu müssen, da die Basiskomponente Änderungen unterliegen könnte und wünschte, diese Änderungen würden sich auch in den abgeleiteten Komponenten widerspiegeln.
Ich habe dieses einfache Beispiel erstellt, um meine Fragen besser zu erklären:
Mit folgender Basiskomponente 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);
}
}
Möchten Sie eine andere abgeleitete Komponente erstellen, ändern Sie beispielsweise nur ein grundlegendes Verhalten der Komponente im Fall der Beispielfarbe 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";
}
}
Vollständiges Arbeitsbeispiel in Plunker
Hinweis: Dieses Beispiel ist offensichtlich einfach und könnte gelöst werden, da sonst keine Vererbung erforderlich ist. Es soll jedoch nur das eigentliche Problem veranschaulichen.
Wie Sie in der Implementierung der abgeleiteten Komponente sehen können app/my-panel.component.ts
, wurde ein Großteil der Implementierung wiederholt, und der einzelne Teil, der wirklich geerbt wurde class
BasePanelComponent
, war der , aber der @Component
musste im Grunde vollständig wiederholt werden, nicht nur die geänderten Teile, wie der selector: 'my-panel'
.
Gibt es eine Möglichkeit, eine Komponente Angular2 buchstäblich vollständig zu vererben, indem beispielsweise die class
Definition der Markierungen / Anmerkungen übernommen wird @Component
?
Bearbeiten 1 - Funktionsanforderung
Feature-Anforderung angular2 wurde dem Projekt auf GitHub hinzugefügt: Erweitern / Erben der Angular2-Komponentenanmerkungen # 7968
Bearbeiten 2 - Geschlossene Anfrage
Aus diesem Grund wurde die Anfrage geschlossen, die kurzzeitig nicht wissen würde, wie der Dekorateur zusammengeführt werden soll. Lassen Sie uns keine Optionen. Meine Meinung wird also in der Ausgabe zitiert .
quelle
Antworten:
Alternative Lösung:
Diese Antwort von Thierry Templier ist eine alternative Möglichkeit, das Problem zu umgehen.
Nach einigen Fragen an Thierry Templier kam ich zu folgendem Arbeitsbeispiel, das meine Erwartungen als Alternative zur in dieser Frage erwähnten Vererbungsbeschränkung erfüllt:
1 - Benutzerdefinierten Dekorateur erstellen:
2 - Basiskomponente mit @Component Decorator:
3 - Unterkomponente mit @CustomComponent Decorator:
Plunkr mit vollständigem Beispiel.
quelle
Angular 2 Version 2.3 wurde gerade veröffentlicht und enthält die native Komponentenvererbung. Es sieht so aus, als könnten Sie alles erben und überschreiben, was Sie wollen, mit Ausnahme von Vorlagen und Stilen. Einige Referenzen:
Neue Funktionen in Angular 2.3
Komponentenvererbung in Winkel 2
Ein Plunkr, der die Vererbung von Komponenten demonstriert
quelle
More than one component matched on this element
Wenn Sie dies nicht tun, wird ein Laufzeitfehler angezeigt .@Component()
Tag haben. Sie können die HTML- oder CSS-Datei jedoch freigeben, indem Sie auf dieselbe Datei verweisen, wenn Sie möchten. Alles in allem ist es ein großes Plus.Jetzt, da TypeScript 2.2 Mixins durch Klassenausdrücke unterstützt, haben wir eine viel bessere Möglichkeit, Mixins auf Komponenten auszudrücken. Beachten Sie jedoch, dass Sie auch die Komponentenvererbung seit Winkel 2.3 ( Diskussion ) oder einen benutzerdefinierten Dekorateur verwenden können, wie in anderen Antworten hier beschrieben. Ich denke jedoch, dass Mixins einige Eigenschaften haben, die sie für die Wiederverwendung des Verhaltens zwischen Komponenten vorziehen:
Ich empfehle dringend, dass Sie die obige TypeScript 2.2-Ankündigung lesen, um zu verstehen, wie Mixins funktionieren. Die verknüpften Diskussionen in eckigen GitHub-Problemen bieten zusätzliche Details.
Sie benötigen diese Typen:
Und dann können Sie ein Mixin wie dieses deklarieren
Destroyable
, mit dessen Hilfe Komponenten Abonnements verfolgen können, die entsorgt werden müssenngOnDestroy
:Um sich
Destroyable
in a zu mischenComponent
, deklarieren Sie Ihre Komponente wie folgt:Beachten Sie, dass dies
MixinRoot
nur erforderlich ist, wenn Sieextend
eine Mixin-Komposition erstellen möchten . Sie können problemlos mehrere Mixins erweitern, zA extends B(C(D))
. Dies ist die offensichtliche Linearisierung von Mixins, über die ich oben gesprochen habe, z. B. wenn Sie effektiv eine Vererbungshierarchie erstellenA -> B -> C -> D
.In anderen Fällen, z. B. wenn Sie Mixins für eine vorhandene Klasse erstellen möchten, können Sie das Mixin folgendermaßen anwenden:
Ich fand jedoch, dass der erste Weg am besten für
Components
und funktioniertDirectives
, da diese auch mit@Component
oder@Directive
sowieso dekoriert werden müssen.quelle
function Destroyable<T extends Constructor<{}>>(Base = class { } as T)
. Auf diese Weise kann ich Mixins mit erstellenextends Destroyable()
.aktualisieren
Die Vererbung von Komponenten wird seit 2.3.0-rc.0 unterstützt
Original
Bisher ist die bequemste für mich Vorlage zu halten und anderen Artikel in separaten
*html
&*.css
Dateien und gibt diejenigen , die durchtemplateUrl
undstyleUrls
, so ist es leicht wiederverwendbar ist.quelle
@Input()
und@Output()
Dekorateure, oder?Soweit ich weiß, wurde die Komponentenvererbung in Angular 2 noch nicht implementiert, und ich bin mir nicht sicher, ob dies geplant ist. Da Angular 2 jedoch Typoskript verwendet (wenn Sie sich für diesen Weg entschieden haben), können Sie die Klassenvererbung verwenden indem du es tust
class MyClass extends OtherClass { ... }
. Für die Vererbung von Komponenten würde ich empfehlen, sich mit dem Angular 2-Projekt zu befassen, indem Sie auf https://github.com/angular/angular/issues gehen und eine Funktionsanfrage senden!quelle
export class MyPanelComponent extends BasePanelComponent
) verwende, besteht das Problem nur im Fall, dass Anmerkungen / Dekorateure nicht vererbt werden.@SubComponent()
) zu haben, der eine Klasse als Unterkomponente kennzeichnet, oder ein zusätzliches Feld im@Component
Dekorator zu haben, mit dem Sie auf eine übergeordnete Komponente verweisen können, von der geerbt werden soll.Lassen Sie uns einige wichtige Einschränkungen und Funktionen des Komponentenvererbungssystems von Angular verstehen.
Die Komponente erbt nur die Klassenlogik:
Diese Funktionen sind sehr wichtig. Lassen Sie uns sie daher einzeln untersuchen.
Die Komponente erbt nur die Klassenlogik
Wenn Sie eine Komponente erben, wird die gesamte darin enthaltene Logik gleichermaßen vererbt. Es ist erwähnenswert, dass nur öffentliche Mitglieder geerbt werden, da auf private Mitglieder nur in der Klasse zugegriffen werden kann, die sie implementiert.
Alle Metadaten im @ Component-Dekorator werden nicht vererbt
Die Tatsache, dass keine Metadaten vererbt werden, mag zunächst kontraintuitiv erscheinen, aber wenn Sie darüber nachdenken, ist dies tatsächlich absolut sinnvoll. Wenn Sie von einem Component say (componentA) erben, möchten Sie nicht, dass der Selektor von ComponentA, von dem Sie erben, den Selektor von ComponentB ersetzt, der die Klasse ist, die erbt. Gleiches gilt für die Vorlage / templateUrl sowie die style / styleUrls.
Die Eigenschaften der Komponenten @Input und @Output werden vererbt
Dies ist eine weitere Funktion, die ich an der Komponentenvererbung in Angular sehr liebe. In einem einfachen Satz werden diese Eigenschaften immer dann vererbt, wenn Sie über eine benutzerdefinierte Eigenschaft @Input und @Output verfügen.
Der Komponentenlebenszyklus wird nicht vererbt
Dieser Teil ist derjenige, der besonders für Menschen, die nicht umfassend mit OOP-Prinzipien gearbeitet haben, nicht so offensichtlich ist. Angenommen, Sie haben ComponentA, das einen der vielen Lifecycle-Hooks von Angular wie OnInit implementiert. Wenn Sie ComponentB erstellen und ComponentA erben, wird der OnInit-Lebenszyklus von ComponentA erst ausgelöst, wenn Sie ihn explizit aufrufen, selbst wenn Sie diesen OnInit-Lebenszyklus für ComponentB haben.
Aufrufen von Super / Base-Komponentenmethoden
Damit die ngOnInit () -Methode von ComponentA ausgelöst wird, müssen wir das Schlüsselwort super verwenden und dann die benötigte Methode aufrufen, die in diesem Fall ngOnInit ist. Das Super-Schlüsselwort bezieht sich auf die Instanz der Komponente, die geerbt wird, von der in diesem Fall ComponentA ist.
quelle
Wenn Sie die CDK-Bibliotheken und die Materialbibliotheken durchlesen, verwenden sie die Vererbung, aber nicht so sehr die Komponenten selbst. Die Projektion von Inhalten ist König IMO. Siehe diesen Link https://blog.angular-university.io/angular-ng-content/, auf dem "das Hauptproblem bei diesem Design" steht.
Ich weiß, dass dies Ihre Frage nicht beantwortet, aber ich denke wirklich, dass das Erben / Erweitern von Komponenten vermieden werden sollte . Hier ist meine Argumentation:
Wenn die um zwei oder mehr Komponenten erweiterte abstrakte Klasse eine gemeinsame Logik enthält: Verwenden Sie einen Dienst oder erstellen Sie sogar eine neue Typoskriptklasse, die von den beiden Komponenten gemeinsam genutzt werden kann.
Wenn die abstrakte Klasse ... gemeinsam genutzte Variablen oder onClicketc-Funktionen enthält, erfolgt eine Duplizierung zwischen dem HTML-Code der beiden erweiterten Komponentenansichten. Dies ist eine schlechte Praxis und das gemeinsam genutzte HTML muss in Komponenten aufgeteilt werden. Diese Komponente (n) (Teile) können zwischen den beiden Komponenten geteilt werden.
Vermisse ich andere Gründe für eine abstrakte Klasse für Komponenten?
Ein Beispiel, das ich kürzlich gesehen habe, waren Komponenten, die AutoUnsubscribe erweitern:
Dies war bas, weil in einer großen Codebasis
infiniteSubscriptions.push()
nur 10 Mal verwendet wurde. Auch das Importieren und Erweitern erfordertAutoUnsubscribe
mehr Code als nur das HinzufügenmySubscription.unsubscribe()
derngOnDestroy()
Methode der Komponente selbst, was ohnehin zusätzliche Logik erfordert.quelle
Wenn jemand nach einer aktualisierten Lösung sucht, ist Fernandos Antwort ziemlich perfekt. Nur dass
ComponentMetadata
dies veraltet ist. VerwendenComponent
stattdessen für mich gearbeitet.Die vollständige Custom Decorator-
CustomDecorator.ts
Datei sieht folgendermaßen aus:Importieren Sie es dann in Ihre neue Komponentendatei
sub-component.component.ts
und verwenden Sie@CustomComponent
stattdessen@Component
Folgendes:quelle
Sie können @Input, @Output, @ViewChild usw. erben. Sehen Sie sich das Beispiel an:
quelle
Komponenten können wie eine Vererbung von Typoskriptklassen erweitert werden, nur dass Sie den Selektor mit einem neuen Namen überschreiben müssen. Alle Input () - und Output () -Eigenschaften der übergeordneten Komponente funktionieren wie gewohnt
Aktualisieren
@Component ist ein Dekorateur,
Dekoratoren werden während der Deklaration der Klasse nicht auf Objekte angewendet.
Grundsätzlich fügen Dekorateure dem Klassenobjekt einige Metadaten hinzu, auf die nicht über die Vererbung zugegriffen werden kann.
Wenn Sie die Vererbung des Dekorateurs erreichen möchten, würde ich vorschlagen, einen benutzerdefinierten Dekorateur zu schreiben. So etwas wie das folgende Beispiel.
Siehe: https://medium.com/@ttemplier/angular2-decorators-and-class-inheritance-905921dbd1b7
quelle
quelle