June 28, 2024

Angular Signals Teil 3 – Welche Vorteile haben Signal Inputs?

Go here for the english version of this blog post.

Steigere die Reaktivität deiner Anwendung mit den Signal Inputs aus Angular 17

In den ersten beiden Beiträgen dieser Artikelreihe, Angular Signals Teil 1 – How-to Guide für Angular Signals und Angular Signals Teil 2 – Wie kombiniert man Angular Signals und RxJS, haben wir uns angeschaut was Angular Signals sind und wie sie sich mit RxJS kombinieren lassen. Aufbauend auf diesem Wissen, wollen wir diesmal die mit der Angular Version 17 eingeführten Signal Inputs genauer betrachten und herausfinden welche Vorteile sie uns in der reaktiven Programmierung bieten. Signal Inputs sind eine reaktive Alternative zu den traditionellen @Input()-Dekoratoren und sollen den Datenaustausch zwischen Child- und Parent-Components vereinfachen. In diesem Blogartikel wird anhand eines Beispiels der klassische @Input()-Dekorator mit dem neuen deklarativen Ansatz der Signal Inputs verglichen und auf die Vorteile der Signal Inputs eingegangen.

Wenn du mehr über Signal Inputs und Angular im Detail erfahren möchtest, besuche einen unserer Angular-Kurse:

Klassischer @Input()-Dekorator

Bevor wir uns näher mit den Signal Inputs beschäftigen, wollen wir einen Blick auf den @Input()-Dekorator werfen. Der @Input-Dekorator in Angular ermöglicht die Übergabe von Daten von einer Parent- zu einer Child-Component. Er wird in der Child-Component verwendet, um eine Property als Input zu markieren, die Daten werden dann von der Parent-Component durch Property Binding bereitgestellt. Dies ist ein grundlegender Bestandteil wiederverwendbarer Komponenten und skalierbarer Angular-Anwendungen, der eine klare Trennung der Verantwortlichkeiten und eine einfache Kommunikation zwischen Komponenten sicherstellt. Weitere Informationen zum @Input()-Dekorator finden sich in der offiziellen Angular Dokumentation. Wir möchten uns das anhand unseres bereits bekannten Beispiels der geraden und ungeraden Zahlen genauer ansehen. Dabei übergibt die Parent-Component eine inkrementierbare Zahl an die Child-Component, sobald sich diese ändert. In der Child-Component wird dann überprüft, ob die Zahl gerade oder ungerade ist.

Parent-Component (main.ts)

Die Parent-Component AppComponent besitzt die Membervariable currentNumber, die durch die Methode increment() erhöht wird. Diese Methode wird durch das Klicken des Buttons im Template ausgelöst. Die Variable wird mittels Property Binding an die Child-Component InputWithDecoratorComponent übergeben.

Child-Component (input-with-decorator.component.ts)

Die Child-Component InputWithDecoratorComponent empfängt eine Zahl von der Parent-Component über den @Input()-Dekorator. Die Berechnung, ob es sich bei dieser Zahl um eine gerade oder ungerade Zahl handelt, wird in der Lifecycle Methode ngOnChanges() überprüft. Diese Methode wird automatisch aufgerufen, wenn sich der Eingabewert unseres @Input()-Dekorator ändert. Anschließend wird im Template angezeigt, ob es sich um eine gerade oder ungerade Zahl handelt.

Signal Inputs mit input()

Signal Inputs sind eine reaktive Alternative zu den traditionellen @Input()-Dekoratoren und sollen den Datenaustausch zwischen Child- und Parent-Component vereinfachen. Sie eignen sich sowohl für Komponenten als auch Direktiven. Die Initialisierung/Deklaration ist sehr simpel:

Der Input kann, wie bei der Variable number, mit einem Wert initialisiert werden. Andernfalls wird, wie bei der Variable name, automatisch undefined verwendet. Bei diesen Signal Inputs handelt es sich um optionale Inputs. Die required Inputs werden im Absatz Optionen behandelt.

Die Klasse InputSignal<T> erweitetert die Signal<T> Klasse und kann dadurch innerhalb des Signal-Kontext verwendet werden. Dadurch können wir auf die Methoden effect() und computed() zugreifen.

@Input() durch Signal Input ersetzen

Nun wollen wir das vorherige Beispiel anhand von Signal Inputs darstellen. Zunächst betrachten wir wieder die Parent-Component. Erfreulicherweise muss nur der Selektor der Komponente angepasst werden. Die Werte können wie bisher per Property Binding im Template an die Child-Component übergeben werden.

Parent-Component (app.component.ts)

computed() statt ngOnChanges()

Bei der Child-Component gibt es ein paar mehr Änderungen:
Die Membervariable number wurde zu einem Signal Input umgewandelt. Anstatt auf Veränderungen durch die ngOnChanges()-Lifecycle Methode zu reagieren, nutzen wir die computed()-Funktion. Die Funktion computed() ist nicht spezifisch für Signal Inputs, sondern kann, wie zuvor erwähnt, für jede Art von Signal verwendet werden. In unseren vorherigen Artikeln haben wir beschrieben, dass es ich dabei um ein readonly Signal handelt, das seinen Wert aus anderen Signals ableitet. Die Funktion wird ausgeführt, sobald sich ein Signal innerhalb der Callback-Funktion ändert. In unserem Fall also, wenn number durch die Parent-Component inkrementiert wird.
Wichtig zu beachten ist, dass auf den Wert eines Signal (Inputs) immer mit einem Funktionsaufruf () zugegriffen wird, ansonsten wird ein Error ausgegeben.

Child-Component (signal-input.component.ts)

Die Funktion effect() ermöglicht es uns festzulegen, welche Aktionen ausgeführt werden sollen, wenn sich der Wert eines Signals ändert oder welche Nebeneffekte auftreten sollen. In unserem Beispiel verwenden wir eine einfache console.log()-Anweisung, die ausgeführt wird, wenn sich das Signal isEven() ändert. Diese Funktion kann besonders nützlich z.B. in Strukturdirektiven verwendet werden, um das Verhalten von DOM-Elementen in Angular basierend auf Bedingungen oder Ereignissen anzupassen oder zu erweitern. Dadurch können DOM-Elemente je nach Bedarf hinzugefügt oder entfernt werden.

Optionen für Signal Inputs

Signal Inputs besitzen die gleichen Optionen wie @Input(). Wir werden nun darauf eingehen wie du diese Optionen bei Signal Inputs verwenden kannst.

required

Um ein Signal Input als erforderlich zu kennzeichnen, können wir required verwenden:

Ohne diese Option ist der Input optional und muss nicht von der Parent-Component übergeben werden. Ist der Signal Input required, erhalten wir einen Error, wenn wir im Parent-Component keinen Wert mitgeben.

alias

Auch einen alias können wir für unser Signal Input bestimmen:

Nun können wir unsere Daten durch Property Binding mit der counter-Property übergeben:

transform()

Mit der Funktion transform() kann der Wert der Input Property transformiert werden, bevor er über das Signal Input ausgegeben wird. Im folgenden Beispiel wird der Input-Wert mit 2 multipliziert, bevor er über das Signal Input ausgegeben wird:

Was sind nun die Vorteile von Signal Inputs?

Signal Inputs bieten eine direkte und reaktive Alternative zu @Input() und damit zahlreiche Vorteile. Der Hauptvorteil zeigt sich besonders, wenn Komponenten bereits in einem reaktiven Stil mit Signals entwickelt wurden. Mit Signal Inputs können nun auch Inputs verwendet werden, die wiederum Signals sind. Dadurch können wir den Funktionsumfang der Signals voll ausnutzen, indem wir computed() und effect() verwenden, um auf Wertveränderungen zu reagieren, anstatt beispielsweise ngOnChanges oder Setter zu verwenden. Ein weiterer Vorteil von Signal Inputs, auf den wir im Beispiel nicht explizit eingegangen sind, ist, dass sie automatisch OnPush Komponenten als dirty markieren, was eine effizientere Aktualisierung der UI ermöglicht. Zudem bieten Signal Inputs die gleichen Optionen wie @Input(), einschließlich der Möglichkeiten, Inputs als required zu kennzeichnen, alias zu verwenden und transform anzuwenden. Die gewohnten Verwendungsmöglichkeiten bleiben also erhalten.

Erfahrung ist der beste Lehrer: Hands-On mit Signal Inputs

Bist Du bereit, die Theorie in die Praxis umzusetzen? In diesem interaktiven StackBlitz-Beispiel befindet sich die vorgestellte Beispielanwendung, die die Grundkonzepte von Signal Inputs aufgreift und alle vorgestellten Beispiele und Funktionen beinhaltet. Tauche ein und experimentiere, um Signals und Signal Inputs in Aktion zu erleben!

Wie es weiter geht

Unsere Reise mit Angular Signals ist noch nicht vorbei. Im nächsten Artikel dieser Reihe wollen wir euch ngxtension und zwei Erweiterungen vorstellen, die uns in der Migration von @Input zu Signal Inputs und @Output sehr geholfen haben und mit der wir effizient und strukturiert auf das neue Signal-basierte Paradigma migrieren konnten.

Terminübersicht der nächsten Angular Schulungen

Related Posts

theCodeCampus Autor Cornelius Rost

Cornelius Rost
Developer at thecodecampus </>

I am Cornelius, a working student in web development at W11K, where I work on web projects and develop practical solutions. I am currently studying for a Master's degree at the University of Stuttgart and am deepening my knowledge of software engineering.


Leave a Reply

Add code to your comment in Markdown syntax.
Like this:
`inline example`

```
code block
example
```

Your email address will not be published.