Rezepte, um mit der Anzeige zu interagieren
In diesem Kapitel geht es um die verschiedenen Möglichkeiten, die uns Angular anbietet, um Daten einer Komponente in der View anzuzeigen. Des Weiteren zeigen wir Möglichkeiten, CSS-Klassen und Styles abhängig von den Daten, die in unserer Komponente liegen, zu ändern. Auch das Ein- und Ausblenden von Teilen des DOMs abhängig von einer Bedingung wird hier gezeigt. Ferner werden wir sehen, wie wir auf Nutzer-Input wie z. B. auf Klicks reagieren können.
Daten einer Komponente in der View anzeigen
Problem
Ich möchte Daten, die sich in meinem TypeScript-Code befinden, in der View anzeigen, damit der Nutzer diese sehen kann.
Zutaten
- Angular 2 Anwendung
- Dummy Daten in der Klasse der Komponente
Lösung 1
1 ...
2
3 @Component({
4 selector: 'app-root',
5 template: `
6 <div>Hello World!</div>
7 <div>My name is {{name}}</div>
8 `
9 })
10 export class AppComponent {
11 name: string;
12
13 constructor() {
14 this.name = 'Max';
15 }
16 }
17 ...
Erklärung:
Um Daten anzuzeigen, müssen wir zwei Sachen machen:
Erstens müssen wir dem Angular-Template sagen, welche Variablen es anzeigen soll. Zweitens müssen wir diese Variablen in unserer Klasse als Eigenschaften definieren.
Um den Code übersichtlicher zu gestalten, nutzen wir hier für die template-Eigenschaft Backticks (`) statt Anführungszeichen (').
Das ermöglicht uns, das Template in mehrere Zeilen aufzuspalten, ohne mehrere Strings mittels Pluszeichen konkatenieren zu müssen.
- Zeile 7: Hier teilen wir Angular mit, das “name” interpoliert werden soll
- Zeile 11: Typdefinition der Komponenten-Eigenschaft
- Zeile 14: Wertzuweisung der name-Eigenschaft. Wichtig ist, dass der Name der Eigenschaft im Template genauso wie in der Klasse geschrieben wird
Lösung 2
1 ...
2
3 @Component({
4 selector: 'app-root',
5 template: `
6 <div>Hello World!</div>
7 <div>My last name is {{lastname}}</div>
8 `
9 })
10 export class AppComponent {
11 lastname = 'Mustermann';
12 }
Erklärung:
In dieser Lösung wird “lastname” nicht im Konstruktor initialisiert, sondern in der Klasse (Zeile 11). Siehe auch TypeScript-Klassen.
Diskussion
Das Beispiel ist sehr einfach gehalten. Die zweite Lösung benötigt weniger Code aber es ist Geschmackssache welche der beiden Varianten wir benutzen. Von der Funktionalität her sind beide gleich. Ein Beispiel mit beiden Schreibweisen gibt es im Code-Beispiel auf Github.
Code
Live Demo auf angular2kochbuch.de
Weitere Ressourcen
- Backticks statt Anführungszeichen für Strings: ECMAScript 6 (2015) Template Strings
- Weitere Informationen zur Interpolation und der Template-Syntax befinden sich in Appendix-A: Template-Syntax
Liste von Daten anzeigen
Problem
Ich hab eine Liste von Benutzerdaten und möchte diese in meine View anzeigen.
Zutaten
- Daten einer Komponente in der View anzeigen
- Eine Liste von Daten
- Die NgFor-Direktive von Angular
Lösung
1 import { Component } from '@angular/core';
2
3 interface User {
4 firstname: string;
5 lastname: string;
6 }
7
8 const users: Array<User> = [
9 { firstname: 'Max', lastname: 'Mustermann' },
10 { firstname: 'John', lastname: 'Doe' }
11 ];
12
13 @Component({
14 selector: 'app-root',
15 template: `
16 <ul>
17 <li *ngFor="let user of users">
18 Name: {{user.firstname}} {{user.lastname}}
19 </li>
20 </ul>
21 `
22 })
23 export class AppComponent {
24 users: Array<User>;
25
26 constructor() {
27 this.users = users;
28 }
29 }
Erklärung:
- Zeilen 3-6: Interfacedefinition für User-Objekte
- Zeile 17: Nutzung der NgFor-Direktive, um eine Liste anzuzeigen
- Zeile 18: Hier nutzen wir die lokale Variable “user”, um Informationen anzuzeigen, wie wir es im Rezept “Daten einer Komponente in der View anzeigen” getan haben
Diskussion
Es gibt noch weitere mögliche Schreibweisen für das Anzeigen einer Liste von Daten. Diese hier ist die Kürzeste und auch vermutlich die Einfachste. Die restlichen Varianten sind im Github Code-Beispiel zu finden. Von der Funktionalität her sind alle Varianten gleich.
Erklärung zu der ngFor-Syntax:
Der Stern (*) vor dem ngFor ist essentiell und Teil der Syntax. Er zeigt an, dass der li-Tag und alle Elemente, die der Tag beinhaltet, als Template für die Instanz der NgFor-Direktive benutzt werden sollen. Der Teil nach dem of ist der Name der Komponenten-Eigenschaft, die unsere Liste referenziert. Das Keyword let definiert eine lokale Template-Eingabevariable für die Instanz der NgFor-Direktive. Diese können wir nur innerhalb des Elementes mit dem ngFor nutzen. Sie hält eine Referenz auf das aktuelle Objekt in der Array.
Code
Live Demo auf angular2kochbuch.de
Weitere Ressourcen
- Offizielle NgFor-Dokumentation auf der Angular 2 Webseite
- Weitere Informationen zu lokalen Variablen und der Template-Syntax gibt es in Appendix A: Template-Syntax
Auf Nutzer-Input reagieren
Problem
Ich möchte in meiner Komponente eine Methode aufrufen, wenn der Nutzer einen Browser-Event wie z. B. “click” auslöst.
Zutaten
- Angular 2 Anwendung
- Ein Browser-Event, wir nutzen hier “click” als Beispiel
- Methode, die aufgerufen werden soll, wenn der Nutzer auf das Element klickt
Lösung 1
1 ...
2
3 @Component({
4 selector: 'app-root',
5 template: '<div (click)="clicked()">Click me</div>'
6 })
7 export class AppComponent {
8 clicked() {
9 console.log('Clicked');
10 }
11 }
Erklärung:
- Zeile 5: Hier findet eine Event-Bindung statt. In diesem Fall wird das click-Event gebunden
- Zeilen 8-10: Die Methode, die aufgerufen werden soll, wenn der Nutzer auf das Element klickt. Zu beachten ist, dass der Name der Methode identisch zu dem Namen, den wir im Template nutzen, sein muss
Lösung 2
1 ...
2
3 @Component({
4 selector: 'app-root',
5 template: '<div on-click="clicked()">Click me</div>'
6 })
7 export class AppComponent {
8 clicked() {
9 console.log('Clicked');
10 }
11 }
Erklärung:
Das ist eine alternative Schreibweise zu der Schreibweise in Lösung 1. Statt Klammern für den Event-Namen nutzen wir hier “on-“ als Präfix. Die Funktionalität bleibt dabei jedoch gleich.
Diskussion
Die Event-Bindung ersetzt alle Event-Direktiven, die es in Angular 1.x gibt wie z. B. “ng-click”, “ng-keypress” und “ng-keydown”. Wir haben im Beispiel “click” benutzt, aber wir hätten auch andere Event-Namen zwischen den Klammern schreiben können wie z. B. “keypress”. Allgemein ist der Namen zwischen den Klammern der Namen des Events, auf das wir reagieren möchten. Nach dem Gleichheitszeichen kommt die Aktion, die als Reaktion zum Event ausgeführt werden soll. Die Event-Bindung ist eine Form der Datenbindung.
Code
Live Demo auf angular2kochbuch.de
Weitere Ressourcen
- Weitere informationen zur Event-Bindung gibt es in Appendix A: Template-Syntax
CSS-Klassen auf Basis von booleschen Werten setzen/entfernen
Problem
Ich möchte anhand eines booleschen Wertes definieren, wann eine CSS-Klasse gesetzt wird und wann nicht.
Zutaten
- Eine Komponente
- CSS-Klassen, die gesetzt bzw. entfernt werden sollen
- Siehe auch Das Template der Komponente vom CSS trennen
- Eigenschaften der Komponente, die wir im Template referenzieren
- NgClass-Direktive von Angular
Lösung 1
1 import { Component } from '@angular/core';
2
3 @Component({
4 selector: 'app-root',
5 styles: [
6 `.box {
7 width: 100px;
8 height: 100px;
9 border: 1px solid black;
10 }`,
11 '.red { background-color: red; }',
12 '.green { background-color: green; }'
13 ],
14 template: `
15 <div class="box" [ngClass]="{red: box.isRed}"></div>
16 <div class="box green" [ngClass]="{green: box.isGreen}"></div>
17 `
18 })
19 export class AppComponent {
20 box = {
21 isRed: true,
22 isGreen: false
23 };
24 }
Erklärung:
- Zeilen 6-12: Definition der CSS-Klassen, die wir benötigen
- Zeilen 15-16: Zwei div-Tags mit CSS-Klassen. Initiale CSS-Klassen werden über das class-Attribut gesetzt. Dynamische CSS-Klassen werden mit Hilfe der ngClass-Eigenschaft gesetzt. Die Eigenschaft bekommt als Wert ein Objekt, dessen Keys die CSS-Klassen sind, die dynamisch hinzugefügt und entfernt werden
- Zeile 15: Durch die input-Eigenschaft “ngClass” wird die CSS-Klasse “red” gesetzt, weil die isRed-Eigenschaft des box-Objektes true ist
- Zeile 16: Durch die input-Eigenschaft “ngClass” wird die CSS-Klasse “green” entfernt, weil die isGreen-Eigenschaft des box-Objektes false ist
- Zeilen 20-23: Objekt mit booleschen Werten, die benutzt werden, um CSS-Klassen im Template hinzuzufügen bzw. zu entfernen
Lösung 2
Wir haben bereits in Lösung 1 gesehen, dass die ngClass-Eigenschaft ein Objekt mit CSS-Klassen als Keys und true/false als Werten bekommt. Statt das Objekt im Template zu definieren, können wir es auch in unserer Klasse definieren.
1 import { Component } from '@angular/core';
2
3 @Component({
4 selector: 'app-root',
5 styles: [
6 `.box {
7 width: 100px;
8 height: 100px;
9 border: 1px solid black;
10 }`,
11 '.red { background-color: red; }'
12 ],
13 template: '<div [ngClass]="classes"></div>'
14 })
15 export class AppComponent {
16 classes = {
17 red: true,
18 box: true
19 };
20 }
Erklärung:
- Zeilen 6-11: Definition der CSS-Klassen, die wir benötigen
- Zeile 13: div-Tag mit ngClass-Eigenschaft, die auf die classes-Eigenschaft der Klasse zugreift
- Zeilen 16-19: Objekt mit CSS-Klassen als Keys und boolesche Werte die angeben, ob die CSS-Klassen gesetzt werden oder nicht
Diskussion
Um das Beispiel möglichst klein zu halten, haben wir hier auf das dynamische Verändern der CSS-Klassen verzichtet. Im Github Code-Beispiel wird gezeigt, wie wir mittels “click” die CSS-Klassen für unsere div-Tags entfernen und hinzufügen können. Um das Code-Beispiel zu verstehen, wird zusätzlich das Rezept “Auf Nutzer-Input reagieren” benötigt.
Wir nutzen hier eine Datenbindung mit eckigen Klammern ([…]). Diese Art der Datenbindung wird Eigenschafts-Bindung genannt. Falls wir nur eine einzige Klasse nutzen, können wir auch eine Klassen-Bindung dafür nutzen.
Code
Code auf Github für die erste Lösung
Live Demo für die erste Lösung auf angular2kochbuch.de
Code auf Github für die zweite Lösung
Live Demo für die zweite Lösung auf angular2kochbuch.de
Weitere Ressourcen
- Offizielle Dokumentation der NgClass-Direktiven
- Weitere Informationen zur Eigenschaften- und Klassen-Bindung gibt es in Appendix A: Template-Syntax
- Informationen zur View-Encapsulation gibt es in unserem Blog
- Eine weitere Möglichkeit, CSS-Styles für eine Komponente zu definieren, gibt es im Rezept “Komponente und CSS trennen”
Teile der View konditional mit NgIf anzeigen
Problem
Ich möchte Teile der View nur dann anzeigen, wenn eine bestimmte Bedingung erfüllt ist.
Zutaten
- Angular 2 Anwendung
- Die NgIf-Direktive von Angular
- Eine Eigenschaft vom Typ “boolean”
Lösung
1 import { Component } from '@angular/core';
2
3 @Component({
4 selector: 'app-root',
5 template: `
6 <div>Hello World!</div>
7 <div *ngIf="showName">
8 <p>My name is Max</p>
9 </div>
10 `
11 })
12 export class AppComponent {
13 showName: boolean;
14
15 constructor() {
16 this.showName = true;
17 }
18 }
Erklärung:
- Zeile 7: Nutzung der NgIf-Direktiven, um den div-Tag nur dann im DOM zu haben, wenn “showName” den Wert true hat
- Zeile 13: Definition der showName-Eigenschaft mit Typ “boolean”
- Zeile 16: Standardmäßig soll die showName-Eigenschaft den Wert true besitzen (div-Tag ist im DOM)
Diskussion
Um das Beispiel möglichst klein zu halten, haben wir hier auf das dynamische Verändern des Wertes der showName-Eigenschaft verzichtet. Im Github Code-Beispiel wird gezeigt wie wir mittels “click” den Wert verändern können. Dort können wir auch sehen, wie sich die View verändert, je nachdem, ob “showName” den Wert true oder false hat.
Es gibt noch weitere mögliche Schreibweisen für das konditionale Anzeigen von Teilen der View mittels der NgIf-Direktive. Die hier verwendete ist die kürzeste und vermutlich die einfachste. Weitere Schreibweisen sind im Github Code-Beispiel zu finden. Von der Funktionalität her sind alle Varianten gleich.
Erklärung zu der ngIf-Syntax
Der Stern (*) vor dem ngIf ist essentiell und Teil der Syntax. Er zeigt an, dass der div-Tag und alle Elemente, die der Tag beinhaltet, als Template für die Instanz der NgIf-Direktiven benutzt werden sollen. Nach *ngIf= kommt ein Angular-Template-Ausdruck, der die Bedingung angibt. Wenn die Evaluation des Ausdruckes true zurückgibt, ist die Bedingung wahr und das Template wird angezeigt. Andernfalls wird das Template aus dem DOM entfernt. Wir haben hier einen sehr einfachen Ausdruck benutzt. Wir hätten auch einen komplexeren Ausdruck nutzen können, z. B. einen, der einen Vergleich mit === beinhaltet.
Code
Live Demo auf angular2kochbuch.de
Weitere Ressourcen
- Offizielle NgIf-Dokumentation auf der Angular 2 Webseite
- Weitere Informationen zu Template-Ausdrücken gibt es in Appendix A: Template-Syntax
Teile der View konditional mit NgSwitch anzeigen
Problem
Ich möchte unterschiedliche Teile der View anzeigen, je nach Wert eines Angular-Ausdrucks.
Zutaten
- Angular 2 Anwendung
- Die NgSwitch-Direktive von Angular
- Die NgSwitchCase-Direktive von Angular
- Die NgSwitchDefault-Direktive von Angular
Lösung
1 import { Component } from '@angular/core';
2
3 @Component({
4 selector: 'app-root',
5 template: `
6 <div [ngSwitch]="color">
7 <p>What color are you?</p>
8 <p *ngSwitchCase="'blue'">I am blue</p>
9 <p *ngSwitchCase="'red'">I am red</p>
10 <p *ngSwitchDefault>Color not known</p>
11 </div>
12 `
13 })
14 export class AppComponent {
15 color: string;
16
17 constructor() {
18 this.color = 'blue';
19 }
20 }
Erklärung:
- Zeile 6: Nutzung der NgSwitch-Direktive mit der color-Eigenschaft der Komponente
- Zeilen 7-10: Inhalt der NgSwitch-Direktiven
- Zeile 7: Wird immer angezeigt unabhängig vom Wert von “color”
- Zeile 8: Wird nur dann angezeigt, wenn “color” den Wert
'blue'hat - Zeile 9: Wird nur dann angezeigt, wenn “color” den Wert
'red'hat - Zeile 10: Wird nur dann angezeigt, wenn “color” irgendeinen Wert außer
'blue'und'red'hat
- Zeile 18: Standardmäßig ist der Wert von “color”
'blue'
Diskussion
Die NgSwitch-Direktive ist vergleichbar mit einer JavaScript switch-Anweisung.
Bei der Nutzung im Template erhält sie über ngSwitch (input-Eigenschaft der NgSwitch-Direktive) einen Angular-Template-Ausdruck, der dann ausgewertet wird.
In unserem Beispiel besteht der Ausdruck aus der color-Eigenschaft.
Diese Auswertung wird dann mit jedem Ausdruck der NgSwitchWhen-Direktiven verglichen.
Angular nutzt für den Vergleich ===.
In unserem Beispiel haben wir 'blue' und 'red' als Ausdrücke für NgSwitchCase benutzt.
Wenn der Vergleich den Wert true zurück gibt, wird der Tag mit der Direktiven und dessen Inhalt angezeigt.
Wenn kein Vergleich true zurück gibt, wird der Tag mit der NgSwitchDefault-Direktiven und dessen Inhalt angezeigt.
Tags, die weder eine NgSwitchCase- noch eine NgSwitchDefault-Direktive nutzen, werden immer angezeigt.
Um das Beispiel möglichst klein zu halten, haben wir hier auf das dynamische Verändern des Wertes der color-Eigenschaft verzichtet. Im Github Code-Beispiel wird gezeigt, wie wir mittels “click” den Wert verändern können. Dort können wir auch sehen, wie sich die View in Abhängigkeit des Wertes der color-Eigenschaft verändert.
Es gibt noch eine weitere mögliche Schreibweise für die NgSwitchCase- und NgSwitchDefault-Direktiven. Diese hier ist die kürzeste und vermutlich die einfachste. Die zweite Schreibweise ist im Github Code-Beispiel zu finden. Von der Funktionalität her sind beide Schreibweisen gleich.
Erklärung zur ngSwitchWhen- und ngSwitchDefault-Syntax
Der Stern (*) vor dem ngSwitchWhen und ngSwitchDefault ist essentiell und Teil der Syntax. Er zeigt an, dass die p-Tags und alle Elemente, die die Tags beinhalten, als Template für die jeweilige Instanz der NgSwitchCase- bzw. der NgSwitchDefault-Direktiven benutzt werden sollen. Nach *ngSwitchCase= kommt ein Angular-Template-Ausdruck. Dieser Ausdruck verglichen mit der Auswertung des NgSwitch-Ausdrucks gibt an, wann das Template angezeigt werden soll. Wenn der Vergleich true ergibt, wird das Template angezeigt. Wenn der false ergibt, wird das Template aus dem DOM entfernt. Das NgSwitchDefault-Template wird nur dann angezeigt, wenn alle Vergleiche false ergeben.
Code
Live Demo auf angular2kochbuch.de
Weitere Ressourcen
- Offizielle NgSwitch-Dokumentation auf der Angular 2 Webseite
- Offizielle NgSwitchCase-Dokumentation auf der Angular 2 Webseite
- Offizielle NgSwitchDefault-Dokumentation auf der Angular 2 Webseite
- Weitere Informationen zur Template-Ausdrücke gibt es in Appendix A: Template-Syntax
Styles eines Elements dynamisch verändern
Problem
Ich möchte die Größe (height/width) eines Elements durch Werte in meiner Komponente definieren. Eine Änderung der Werte in der Komponente soll auch die Größe des Elements verändern.
Zutaten
- Angular 2 Anwendung
- Eigenschaften in der Komponente, die wir im Template referenzieren
- NgStyle-Direktive von Angular
Lösung 1
1 import { Component } from '@angular/core';
2
3 @Component({
4 selector: 'app-root',
5 template: `
6 <div [ngStyle]="{'width': elemWidth, 'height': elemHeight}"
7 style="background-color: red"></div>
8 `
9 })
10 export class AppComponent {
11 elemWidth: string;
12 elemHeight: string;
13 constructor() {
14 this.elemWidth = '100px';
15 this.elemHeight = '100px';
16 }
17 }
Erklärung:
- Zeilen 6-7: div-Tag mit Styles. Statische Styles werden über das style-Attribut gesetzt. Dynamische Styles werden mit Hilfe der ngStyle-Eigenschaft, einer input-Eigenschaft der NgStyle-Direktive, gesetzt. Die Eigenschaft erhält als Wert ein Objekt dessen Keys die style-Eigenschaften sind, die gesetzt werden (hier width und height). Die Werte für die Styles sind in der Klasse der Komponente definiert (siehe Zeilen 14 und 15)
- Zeile 14: Der Wert für die Breite des Elements
- Zeile 15: Der Wert für die Höhe des Elements
Lösung 2
Wir haben bereits in Lösung 1 gesehen, dass die ngStyle-Eigenschaft ein Objekt mit style-Eigenschaften als Keys und Werten für die Styles als Werte für die Keys bekommt. Statt Werte individuell in der Klasse zu definieren, können wir auch direkt das Objekt für die ngStyle-Eigenschaft definieren.
1 import { Component } from '@angular/core';
2
3 interface Dimensions {
4 width: string;
5 height: string;
6 }
7
8 @Component({
9 selector: 'app-root',
10 template: `
11 <div [ngStyle]="dimensions" style="background-color: red"></div>
12 `
13 })
14 export class AppComponent {
15 dimensions: Dimensions;
16 constructor() {
17 this.dimensions = {
18 width: '100px',
19 height: '100px'
20 };
21 }
22 }
Erklärung:
- Zeile 11: div-Tag mit ngStyle-Eigenschaft, die auf die dimensions-Eigenschaft der Klasse zugreift
- Zeilen 17-20: Objekt mit style-Eigenschaften als Keys und Werten, die die Werte für die Styles definieren
Diskussion
Um das Beispiel möglichst klein zu halten, haben wir hier auf das dynamische Verändern der Werte der style-Eigenschaften verzichtet. Im Github-Code-Beispiel wird gezeigt, wie wir mittels “click” die Werte der styles-Eigenschaften verändern können. Um das Code-Beispiel zu verstehen, wird auch das Rezept “Auf Nutzer-Input reagieren” benötigt.
Wir nutzen hier eine Datenbindung mit eckigen Klammern ([…]). Diese Art der Datenbindung wird Eigenschafts-Bindung genannt. Falls wir nur eine einzige styles-Eigenschaft setzen, können wir auch eine Style-Bindung dafür nutzen.
Code
Code auf Github für die erste Lösung
Live Demo für die erste Lösung auf angular2kochbuch.de
Code auf Github für die zweite Lösung
Live Demo für die zweite Lösung auf angular2kochbuch.de
Weitere Ressourcen
- Offizielle Dokumentation der NgStyle-Direktiven
- Weitere Informationen zur Eigenschaften- und Klassen-Bindung gibt es in Appendix A: Template-Syntax