Zu diesem Buch – sowie zu vielen weiteren O’Reilly-Büchern – können Sie auch das entsprechende E-Book im PDF-Format herunterladen. Werden Sie dazu einfach Mitglied bei oreilly.plus+:

www.oreilly.plus

3. AUFLAGE

Angular

Das Praxisbuch zu Grundlagen und Best Practices

Manfred Steyer

Manfred Steyer

Lektorat: Ariane Hesse

Bibliografische Information der Deutschen Nationalbibliothek

ISBN:

3. Auflage 2021

Dieses Buch erscheint in Kooperation mit O’Reilly Media, Inc. unter dem Imprint »O’REILLY«.

Hinweis:

Schreiben Sie uns:

Die vorliegende Publikation ist urheberrechtlich geschützt. Alle Rechte vorbehalten. Die Verwendung der Texte und Abbildungen, auch auszugsweise, ist ohne die schriftliche Zustimmung des Verlags urheberrechtswidrig und daher strafbar. Dies gilt insbesondere für die Vervielfältigung, Übersetzung oder die Verwendung in elektronischen Systemen.

5 4 3 2 1 0

Inhalt

Vorwort

1Projekt-Setup

Visual Studio Code

Angular CLI

Node.js und Angular CLI installieren

Ein Projekt mit der CLI generieren

Angular-Anwendung starten

Build mit CLI

Projektstruktur von CLI-Projekten

Internet Explorer 11

Eine Style-Bibliothek installieren

Alternativen zu Bootstrap

Zusammenfassung

2Erste Schritte mit TypeScript

Motivation

Mit TypeScript starten

Hallo Welt!

Variablen deklarieren

Ausgewählte Datentypen in TypeScript

Ein erstes Objekt samt Modul

Auto-Importe mit Visual Studio Code

Klassen

Funktionen und Lambda-Ausdrücke

Interfaces und Vererbung

Interfaces

Klassenvererbung

Type Assertion (Type Casting)

Abstrakte Klassen

Zugriff auf die Basisklasse

Ausgewählte Sprachmerkmale

Getter und Setter

Generics

Exceptions

Spread-Operator

Strikte Null-Prüfungen

Asynchrone Operationen

Callbacks und die Pyramide of Doom

Promises

async und await

Bedeutung von Promises in Angular

Zusammenfassung

3Eine erste Angular-Anwendung

Angular-Komponente erzeugen

Komponentenlogik

Auf das Backend zugreifen

Templates und die Datenbindung

Two-Way-Binding

Property-Bindings

Direktiven

Pipes

Event-Bindings

Das gesamte Template

Komponenten einbinden

Anwendung ausführen und debuggen

Anwendung starten

Fehler in der Entwicklerkonsole entdecken

Die Anwendung im Browser debuggen

Debuggen mit Visual Studio Code

Zusammenfassung

4Komponenten und Datenbindung

Datenbindung in Angular

Rückblick auf AngularJS 1.x

Property-Binding

Event-Bindings

Das Zusammenspiel von Property- und Event-Bindings

Bindings im Template

Two-Way-Bindings

Eigene Komponenten mit Datenbindung

Überblick

Vorbereitungen

Eine Komponente mit Property-Bindings

Komponenten mit Event-Bindings

Komponenten mit Two-Way-Bindings

Life-Cycle-Hooks

Ausgewählte Hooks

Experiment mit Life-Cycle-Hooks

Angular und Zyklen

DateControl mit Life-Cycle-Hooks

Zusammenfassung

5Services und Dependency Injection

Ein erster Service

Services austauschen

Services mit klassischen Providern konfigurieren

Einen Service lokal registrieren

Arten von Providern

useClass

useValue

useFactory

useExisting

multi

Konstanten als Tokens

Zusammenfassung

6Pipes

Überblick

Built-in-Pipes

Eigene Pipes

Pure Pipes

Implementierung einer einfachen Pipe

Pipes registrieren und nutzen

Weiterführende Konstellationen

Pipes und Objekte

Pipes und Direktiven

Pipes und Services

Aufräumarbeiten mit ngOnDestroy

Zusammenfassung

7Module

Motivation

Eine Angular-typische Modulstruktur

Shared Modules

Feature-Modules

Root-Modules

Module reexportieren

Zusammenfassung

8Routing

Überblick

Erste Schritte mit dem Router

Routing-Konfiguration für das AppModule einrichten

Routing-Konfiguration für Feature-Modules einrichten

Platzhalter in AppComponent hinterlegen

Hyperlinks zum Aktivieren von Routen einrichten

Parametrisierte Routen

Arten von Routing-Parametern

Parameter in Komponenten auslesen

Parametrisierte Routen konfigurieren

Auf parametrisierte Routen verweisen

Hierarchisches Routing mit Child-Routes

Überblick über Child-Routes

Child-Komponente implementieren

Child-Komponente registrieren

Hyperlinks zum Aktivieren von Child-Routen einrichten

Aux-Routes

Platzhalter für Aux-Routes

Komponente für Aux-Route erzeugen

Konfiguration für Aux-Route

Verweise auf Aux-Routes einrichten

Mit dem Query-String und dem Hash-Fragment arbeiten

QueryString und Hash-Fragment programmatisch beeinflussen

Query-String und Hash-Fragment deklarativ beeinflussen

Query-String und Hash-Fragment auslesen

HTML5-Routing vs. Hash-Routing

PathLocationStrategy

HashLocationStrategy

Zusammenfassung

9Template-getriebene Formulare und Validierung

FormsModule einbinden

Eingaben validieren

Zugriff auf den Zustand des Formulars

Bedingte Formatierung von Eingabefeldern

Eigene Validierungsdirektiven

Eine erste Validierungsdirektive erstellen

Parametrisierbare Validierungsdirektiven

Multi-Field-Validatoren erstellen

Asynchrone Validatoren

Komponente zum Präsentieren von Validierungsfehlern

Die Standardsteuerelemente von HTML nutzen

Checkboxen

Radiobuttons

Drop-down-Felder

Zusammenfassung

10Reaktive Formulare

Erste Schritte mit reaktiven Formularen

Modul einbinden

Das Formular mit einem Objektgraphen beschreiben

Reactive Formulare mit dem FormBuilder beschreiben

Einen Objektgraphen an ein Formular binden

Werte ins Formular schreiben

Validatoren

Synchrone Validatoren

Parametrisierte Validatoren

Asynchrone Validatoren

Multi-Field-Validatoren für reaktive Formulare

Geschachtelte Formulare

Geschachtelte FormGroups

Wiederholgruppen mit FormArray

Dynamische Formulare

Zusammenfassung

11Reactive Extensions Library for JavaScript (RxJS)

Grundlegende Typen von RxJS

Observables, Observer und Operatoren

Observables instanziieren

Subjects

Observables vs. Promises

Observables in Promises umwandeln

Promises in Observables umwandeln

Gruppen von Operatoren

Creation Operators

Transformation Operators

Filtering Operators

Join Operators

Error Handling Operators

Multicasting Operators

Utility Operators

Reaktiver Entwurf

Flattening

Datenflüsse kombinieren

Der Operator combineLatest

combineLatest vs. withLatestFrom

Der Operator merge

Multicasting

Motivation für Multicasting

Hot vs. Cold Observables

Fehlerbehandlung

Observables schließen

Reaktive Services

Zusammenfassung

12Testautomatisierung

Jasmine und Karma

Aufbau eines Jasmine-Tests

Tests mit Karma ausführen

Karma auf dem Build-Server

Angular und Jasmine

Komponenten mit dem TestBed testen

Arbeiten mit Attrappen (Mocks)

Gray-Box-Tests mit Spys

HTTP-Zugriffe simulieren

Asynchrone Tests

Templates mit DOM-Zugriffen testen

Direktiven testen

Pipes testen

Testabdeckung ermitteln

Zusammenfassung

13Performancetuning

Optimierte Datenbindung mit OnPush

Datenbindung visualisieren

Immutables

Immutables und Datenbindung

Observables und Datenbindung

Immutables und/oder Observables

Manuelle Änderungsverfolgung

Lazy Loading von Routen

Routen für das Lazy Loading einrichten

Lazy Loading im Browser nachvollziehen

Lazy Loading und Tree-Shakable Provider

Lazy Loading, klassische Provider und Shared Modules

Korrekte Nutzung von SharedModules beim Einsatz von Lazy Loading

Preloading

Preloading aktivieren

Eigene Preloading-Strategien entwickeln

Selektives Preloading mit eigener Preloading-Strategie

Zusammenfassung

14.Querschnittsfunktionen

Guards

Das Aktivieren von Routen verhindern

Das Deaktivieren einer Komponente verhindern

Events

Resolver

Vorbereitungen

Resolver erzeugen und verwenden

HttpInterceptoren

Zusammenfassung

15.Authentifizierung und Autorisierung

Cookie-basierte Security

Cookies und XSRF

Tokenbasierte Security

OAuth 2 und OpenID Connect

OAuth 2

Benutzer mit OpenID Connect authentifizieren

JSON Web Token

OAuth-2- und OIDC-Flows

OAuth 2 und OIDC mit Angular nutzen

Zusammenfassung

16Internationalisierung

I18N mit dem Angular-Compiler

Überblick

@angular/localize installieren

Texte markieren

Strings in der Komponentenklasse markieren

Texte extrahieren

Übersetzte Texte in Builds integrieren

Sprache beim Einsatz von ng serve festlegen

Übersetzungstexte zur Laufzeit angeben

Grammatikalische Formen berücksichtigen

Unterschiedliche Formate unterstützen

Manuell weitere Formate laden

ngx-translate

Überblick

Bibliothek installieren und konfigurieren

Sprachdateien bereitstellen

Texte einbinden

Texte zur Laufzeit laden

Sprachwechsel

Grammatikalische Formen berücksichtigen

Unterschiedliche Formate nutzen

Lazy Loading

Zusammenfassung

17Reaktive Zustandsverwaltung mit NGRX (Redux)

Zustandsverwaltung mit Services

Das Redux-Muster

NGRX einrichten

Building-Blocks implementieren

State modellieren

Actions festlegen

Reducer definieren

Effect einrichten

Auf den Store zugreifen

Debuggen mit dem Store

Selektoren

Ein erster Selektor

Selektoren verschachteln

Meta-Reducer

Zusammenfassung

18Details zu Komponenten und Direktiven

Vorbereitungen

Weiterführende Aspekte von Komponenten

Content Projection

Parent-Komponenten referenzieren

View und Content

Kommunikation über Template-Variablen

Kommunikation über Services

Attributdirektiven

Direktiven definieren

Mit der Umwelt kommunizieren

Direktiven und Template-Variablen

Strukturelle Direktiven

Templates und Container

Microsyntax

Eine einfache DataTable umsetzen

ViewContainerRef direkt zum Einblenden von Templates verwenden

Bestehende ViewContainer ergänzen

Dialoge dynamisch einblenden

ViewContainerRef direkt zum dynamischen Erzeugen von Komponenten verwenden

Komponenten für Formularfelder

Ausgaben formatieren und Eingaben parsen

Eigene Formularsteuerelemente

Zusammenfassung

19Wiederverwendbare Bibliotheken und Monorepos

Monorepo erstellen

Aufbau von Bibliotheken

Bibliothek in Monorepo ausprobieren

npm-Paket bauen und bereitstellen

npm-Paket konsumieren

Zusammenfassung

Index

Vorwort

Vor etwas mehr als zehn Jahren galt für gute Webanwendungen noch die Regel, so viele Aufgaben wie möglich auf dem Server zu erledigen. Inzwischen stützen sich moderne Webanwendungen jedoch auf clientseitige Techniken, allen voran JavaScript. Dies steigert die Benutzerfreundlichkeit und schafft die Möglichkeit, die jeweilige Anwendung an die Auflösungen und Formfaktoren der vielen unterschiedlichen klassischen und mobilen Plattformen anzupassen.

Single Page Applications (SPAs) bilden einen derzeit äußerst beliebten Architekturstil für solche Webanwendungen. Wie ihr Name schon vermuten lässt, bestehen SPAs aus lediglich einer einzigen Seite, die ein Browser auf klassischem Weg abruft und anzeigt. Alle weiteren Seiten und Daten bezieht die SPA bei Bedarf über direkte HTTP-Zugriffe per JavaScript.

Das populäre JavaScript-Framework Angular, das von Google entwickelt wird, hilft Ihnen beim Erstellen von Anwendungen, die diesen Architekturstil verfolgen. Angular bietet unter anderem Unterstützung für die Datenbindung, für das Validieren von Daten sowie das Arbeiten mit Vorlagen. Darüber hinaus stellt Angular Konzepte zur Verfügung, mit denen Sie den Quellcode strukturieren und wartbare, wiederverwendbare sowie testbare Programmteile erschaffen können. Das vorliegende Buch präsentiert die Möglichkeiten von Angular. Dabei beschränkt es sich nicht nur auf die Grundlagen, sondern geht auch auf die zugrunde liegenden Konzepte ein.

Zielgruppe

Das Buch richtet sich an Entwickler, die bereits grundlegende Erfahrungen mit HTML, CSS und JavaScript gesammelt haben und nun mit Angular SPAs entwickeln wollen. Dabei bezieht es sich auf die Version 12 von Angular, die beim Verfassen der Texte die aktuellste Version war. Aufgrund des evolutionären Charakters von Angular gehen wir jedoch davon aus, dass dieses Buch auch für viele darauffolgende Versionen geeignet ist.

Zielsetzung des Buchs

Mit diesem Buch verfolgen wir das Ziel, Ihnen anhand von Beispielen zu zeigen, wie Sie Angular zur Entwicklung von Single Page Applications nutzen können. Dabei gehen wir auf die Möglichkeiten von Angular ein und präsentieren auch Lösungen für Aspekte, die Angular nicht direkt unterstützt.

Quellcodebeispiele, Onlineservices und Errata

Über http://www.ANGULARarchitects.io/leser stellen wir Ihnen sämtliche in diesem Buch präsentierten Quellcodebeispiele sowie Web-APIs zur Verfügung, die die Beispiele zu Demonstrationszwecken nutzen und die Sie auch in eigene Projekte einbinden können. Darüber hinaus werde ich auf dieser Seite weitere Informationen zu Angular sowie gegebenenfalls Errata zum vorliegenden Buch veröffentlichen. Daneben bietet die Website Ihnen die Möglichkeit, mit mir als Autor direkt in Kontakt zu kommen.

Konventionen

Kursiv

Wird genutzt für neue Begriffe, URLs, Dateinamen und E-Mail-Adressen

Nichtproportionalschrift

Programmlistings und Codeelemente im Fließtext wie Methoden, Module o.Ä. werden in dieser Schrift dargestellt.

Dieses Symbol steht für Hinweise und allgemeinere Anmerkungen.

Dieses Symbol steht für Tipps.

Aufbau des Buchs

Das Buch besteht aus 19 Kapiteln. Die folgende Auflistung zeigt, was diese bieten:

Schulungen und Beratung

Der Autor bietet Schulungen und Beratung zu Angular an. Informationen dazu finden Sie unter http://www.ANGULARarchitects.io.

Danksagungen

Meinen Dank für ihre Mitwirkung an diesem Buch möchte ich aussprechen an

KAPITEL 1

Projekt-Setup

Moderne JavaScript-Projekte gleichen immer mehr klassischen Anwendungen: Sie nutzen Compiler, um moderne typsichere Sprachen wie TypeScript in handelsübliches JavaScript zu übersetzen. Zusätzlich verwenden sie Werkzeuge, mit denen sie optimierte Bundles erzeugen. Damit sind JavaScript-Dateien gemeint, die sich aus mehreren einzelnen Dateien zusammensetzen.

Durch dieses Vorgehen müssen nur noch wenige Dateien auf dem Server platziert sowie in den Browser geladen werden. Ersteres erhöht den Komfort beim Deployment, und Letzteres verbessert die Startgeschwindigkeit der Anwendung. Außerdem kommen in modernen JavaScript-Projekten auch Werkzeuge zur Testautomatisierung zum Einsatz.

Dieses Kapitel zeigt, wie sich ein Projekt-Setup für Angular, das diesen Kriterien genügt, einrichten lässt. Es beginnt mit der Installation und Einrichtung von Visual Studio Code, der in diesem Buch verwendeten Entwicklungsumgebung. Danach wendet sich das Kapitel dem Angular Command Line Interface (CLI) zu. Dabei handelt es sich um eine vom Angular-Team bereitgestellte Konsolenanwendung, die viele Aufgaben rund um die Angular-Entwicklung automatisiert. Schließlich erfahren Sie in diesem Kapitel auch, wie ein mit der CLI generiertes Projekt aufgebaut ist.

Visual Studio Code

Wir nutzen in diesem Buch die freie Entwicklungsumgebung Visual Studio Code (https://code.visualstudio.com). Sie funktioniert auf allen wichtigen Betriebssystemen (Linux, macOS, Windows) und ist äußerst leichtgewichtig. Visual Studio Code unterstützt auch die Sprache TypeScript. Bei dieser handelt es sich um eine typsichere Obermenge von JavaScript, die für die Angular-Entwicklung verwendet wird.

Außerdem existieren zahlreiche Erweiterungen, die die Arbeit mit Frameworks wie Angular vereinfachen. Um Erweiterungen zu installieren, klicken Sie auf das Symbol Extensions in der linken Symbolleiste. Anschließend können Sie nach Erweiterungen suchen und diese installieren (siehe Abbildung 1-1).

Abbildung 1-1: Erweiterungen in Visual Studio Code installieren

Für die Entwicklung von Angular-Lösungen empfehlen wir die folgenden Erweiterungen:

Angular Language Service

Der Angular Language Service wird vom Angular-Team bereitgestellt und erlaubt Angular-bezogene Codevervollständigungen in HTML-Templates. Außerdem weist der Language Service auch auf mögliche Fehler in HTML-Templates hin.

Angular Schematics

Erlaubt das Generieren von Building-Blocks wie Angular-Komponenten über das Kontextmenü von Visual Studio Code.

Debugger for Chrome

Erlaubt das Debuggen von JavaScript-Anwendungen, die in Chrome ausgeführt werden.

Bitte installieren Sie diese Erweiterungen. Wir werden bei Bedarf in den einzelnen Kapiteln darauf zurückkommen.

Neben Visual Studio Code haben wir auch mit den kommerziellen Produkten WebStorm, PhpStorm bzw. IntelliJ von Jetbrains (https://www.jetbrains.com/) sehr gute Erfahrungen gemacht. Es handelt sich bei diesen drei Lösungen eigentlich um das gleiche Produkt in verschiedenen Ausprägungen. PhpStorm unterstützt zum Beispiel darüber hinaus PHP, während IntelliJ zusätzlich viele Annehmlichkeiten für Java-Entwickler mit sich bringt. Diese Lösungen sind zwar etwas schwergewichtiger als Visual Studio Code, bieten dafür jedoch ab Werk zahlreiche Features, wie umfangreiche Refactoring-Möglichkeiten oder Test-Runner für Unit-Tests.

Tatsächlich sind Visual Studio Code und WebStorm/IntelliJ mit Abstand die am häufigsten eingesetzten Entwicklungsumgebungen, auf die wir bei unseren Kundenprojekten im Angular-Umfeld stoßen.

Angular CLI

Um keine Zeit mit dem Einrichten aller benötigten Werkzeuge zu verlieren, bietet das Angular-Team das sogenannte Angular Commandline Interface, kurz Angular CLI (Angular CLI (https://cli.angular.io)), an. Die CLI generiert nicht nur das Grundgerüst der Anwendung, sondern auf Wunsch auch die Grundgerüste weiterer Anwendungsbestandteile wie z.B. Komponenten.

Außerdem kümmert sie sich um das Konfigurieren des TypeScript-Compilers und einer Build-Konfiguration zur Erzeugung optimierter Bundles. Werkzeuge für die Testautomatisierung richtet die CLI ebenfalls ein.

Node.js und Angular CLI installieren

Die CLI lässt sich leicht über den Package-Manager npm beziehen, der sich im Lieferumfang von Node.js (nodejs.org) befindet. Außerdem nutzt sie Node.js als Laufzeitumgebung. Deswegen sollten Sie zur Vorbereitung eine aktuelle Node.js-Version von Node.js (https://nodejs.org) herunterladen und installieren. Die Autoren haben gute Erfahrungen mit den jeweiligen Long-Term-Support-Versionen (LTS-Versionen) gemacht. Der Einsatz älterer Versionen kann zu Problemen führen.

Sobald Node.js installiert ist, kann die CLI mittels npm eingerichtet werden:

npm install -g @angular/cli

Der Schalter -g bewirkt, dass npm das Werkzeug systemweit, also global, einrichtet, sodass es überall zur Verfügung steht. Ohne diesen Schalter würde npm das adressierte Paket lediglich für ein lokales Projekt im aktuellen Ordner einrichten. Nach der Installation steht die CLI über das Kommando ng zur Verfügung.

Ein Projekt mit der CLI generieren

Ein Aufruf von

ng new flight-app

generiert das Grundgerüst einer neuen Angular-Anwendung, die den Namen flight-app erhält. Dazu stellt es uns ein paar Fragen (siehe Abbildung 1-2):

Abbildung 1-2: ng new stellt ein paar Fragen, bevor es ein neues Projekt generiert.

Je nach Angular-Version können diese Fragestellungen etwas variieren. Wir gehen hier von folgenden Einstellungen aus:

Add Angular Routing

Diese Frage beantworten wir hier mit No. Um das Thema Routing kümmert sich Kapitel 8.

Stylesheet Format

Wir empfehlen hier SCSS, eine Obermenge von CSS. Die Angular CLI kompiliert diese Dateien für den Browser nach CSS.

Da ng new auch zahlreiche Pakete via npm bezieht, kann der Aufruf etwas länger dauern.

Seit Version 12 verwendet die CLI standardmäßig den sogenannten Strict Mode. In diesem Modus führen sowohl der TypeScript-Compiler als auch Angular selbst strengere Code-Prüfungen durch. Hierdurch sollen Programmierfehler rascher entdeckt werden.

Falls Sie diese strengeren Prüfungen nicht verwenden wollen, verwenden Sie den Schalter --strict:

ng new flight-app --strict false

Wir gehen in in diesem Buch jedoch davon, dass der Strict Mode aktiviert ist. Das entspricht auch den Empfehlungen des Angular-Teams.

Angular-Anwendung starten

Um Ihre Anwendung zu starten, wechseln Sie in den generierten Projektordner. Dort bauen Sie mit ng serve die Anwendung und stellen sie über einen Demowebserver bereit:

cd flight-app

ng serve -o

Der Schalter -o öffnet einen Browser, der die Anwendung anzeigt. Standardmäßig findet sich diese Anwendung unter http://localhost:4200. Ist Port 4200 schon belegt, erkundigt sich ng serve nach einer Alternative. Außerdem nimmt der Schalter --port den gewünschten Port gleich beim Start von ng serve entgegen:

ng serve -o --port 4242

Die im Browser angezeigte Anwendung sieht wie in Abbildung 1-3 aus. Auch hier kann es von Version zu Version zu Abweichungen kommen.

Abbildung 1-3: Generierte Angular-Anwendung

Der für die Entwicklung gedachte Befehl ng serve macht aber noch ein wenig mehr: Er überwacht sämtliche Quellcodedateien und stößt das Kompilieren sowie Generieren der Bundles erneut an, wenn sie sich ändern. Danach aktualisiert er auch das Browserfenster.

Um das auszuprobieren, können Sie mit Visual Studio Code die Datei src\app\app.component.html öffnen und das erste Vorkommen von Welcome durch Hello World! ändern. Nach dem Speichern der Datei sollte ng serve den betroffenen Teil der Anwendung neu kompilieren, bundeln und den Browser aktualisieren (siehe Abbildung 1-4).

Abbildung 1-4: Generierte Angular-Anwendung ändern

Wenn Sie Visual Studio Code verwenden, sollten Sie zunächst den Hauptordner Ihrer Angular-Anwendung mit dem Befehl File/Open Folder öffnen. Der Hauptordner ist der, der auch die Datei package. json beinhaltet. Das stellt sicher, dass Visual Studio Code sämtliche Konfigurationsdateien findet und keine unnötigen Fehler anzeigt.

Danach können Sie die gewünschte Datei über den links angezeigten Explorer suchen und öffnen. Alternativ dazu bietet sich die Tastenkombination Strg+P an. Sie öffnet ein kleines Fenster, mit dem man nach der gewünschten Datei suchen kann.

Mit Strg+Umschalt+C können Sie übrigens jederzeit eine externe Konsole im aktuellen Ordner öffnen, um z.B. die Angular CLI auszuführen. Die Tastenkombination Strg+Umschalt+Ö öffnet hingegen die Konsole als Terminal direkt in Visual Studio Code.

Die automatische Generierung der Bundles nach einer Änderung am Programmcode funktioniert meist ganz gut, aber ab und an kommt die CLI aus dem Tritt. Das ist unter anderem dann der Fall, wenn Sie mehrere Dateien rasch hintereinander speichern. Auch das Umbenennen von Dateien bringt diesen Mechanismus aus dem Konzept.

Abhilfe schafft hier ein erneutes Speichern der betroffenen Dateien oder – wenn alle Stricke reißen – ein Neustart von ng serve.

Build mit CLI

Während ng serve für die Entwicklung sehr komfortabel ist, eignet es sich nicht für den Produktiveinsatz. Um Bundles für die Produktion zu generieren, nutzen Sie die Anweisung

ng build

Seit Angular CLI 12 führt ng build zahlreiche Optimierungen, die zu kleineren Bundles führen, automatisch durch. Davor musste man diese Optimierungen explizit mit dem Schalter --prod anfordern.

Ein Beispiel für eine solche Optimierung ist die Minifizierung, bei der unnötige Zeichen wie Kommentare oder Zeilenschaltungen entfernt sowie Ihre Anweisungen durch kompaktere Darstellungsformen ersetzt werden. Ein weiteres Beispiel ist das sogenannte Tree-Shaking, das nicht benötigte Framework-Bestandteile identifiziert und entfernt. Diese Optimierungen verlangsamen natürlich den Build-Prozess ein wenig.

Die generierten Bundles finden sich im Ordner dist/flight-app. Im Rahmen der Bereitstellung müssen Sie diese Dateien lediglich auf den Webserver Ihrer Wahl kopieren. Da es sich aus Sicht des Webservers hierbei um eine statische Webanwendung handelt, müssen Sie dort auch keine zusätzliche Skriptsprache und kein Web-Framework installieren.

Projektstruktur von CLI-Projekten

Die von der CLI generierte Projektstruktur orientiert sich an Best Practices, die sich auch in anderen Projekten finden. Für einen ersten Überblick präsentiert Tabelle 1-1 die wichtigsten Dateien. Wir gehen im Laufe des Buchs auf diese und weitere Dateien bei Bedarf genauer ein.

Tabelle 1-1: Projektstruktur

Ordner/Datei

Beschreibung

src/

Beinhaltet alle Quellcodedateien (TypeScript, HTML, CSS etc.).

src/main.ts

Dieser Quellcodedatei kommt besondere Bedeutung zu. Die CLI nutzt sie als Einstiegspunkt in die Anwendung. Deswegen wird ihr Code beim Programmstart zuerst ausgeführt. Standardmäßig beinhaltet sie ein paar Zeilen zum Starten von Angular. Normalerweise müssen Sie diese Datei nicht anpassen.

src/styles.scss

Hier können Sie Ihre eigenen globalen Styles eintragen. Die Dateiendung, z.B. css oder scss, hängt von der beim Generieren des Projekts gewählten Option ab.

src/app/

Dieser Ordner und seine Unterordner beinhalten die entwickelten Programmdateien wie zum Beispiel Angular-Komponenten.

src/assets/

Ordner mit statischen Dateien, die die CLI beim Build in das Ausgabeverzeichnis kopiert. Hier könnten Sie zum Beispiel Bilder oder JSON-Dateien ablegen.

dist/

Beinhaltet die von ng build generierten Bundles für die Auslieferung auf einen Server. Der Einsatz von ng serve schreibt diese Bundles hingegen nicht auf die Platte, sondern hält sie lediglich im Hauptspeicher vor.

node_modules/

Beinhaltet sämtliche Module, die über npm bezogen wurden. Dazu gehören der TypeScript-Compiler und andere Werkzeuge für den Build, aber auch sämtliche Bibliotheken für Angular.

tsconfig.json

Konfigurationsdatei für TypeScript. Hier wird zum Beispiel festgelegt, dass der TypeScript-Compiler Ihren Quellcode nach ECMAScript 2015 kompilieren soll. Das ist jene JavaScript-Version, die von allen modernen Browsern der letzten Jahre unterstützt wird.

.browserslistrc

Listet sämtliche Browser, die die Angular-Anwendung unterstützen soll. Aus dieser Liste ermittelt die Angular CLI nötige CSS-Präfixe, die es beim Kompilieren einfügt. Bis Angular 12 wurde aus dieser Datei auch abgeleitet, ob zusätzlich Legacy-Bundles (ECMAScript 5) für Browser wie Internet Explorer 11 zu erzeugen sind.

package.json

Referenziert sämtliche Bibliotheken, die benötigt werden, inklusive der gewünschten Versionen. Wenn Sie einen Blick auf die Abschnitte dependencies und devDependencies werfen, sehen Sie alle von ng new installierten Pakete. Da der Ordner node_modules mit diesen Paketen nicht in die Quellcodeverwaltung eingecheckt wird, sind diese Hinweise notwendig. Ihre Entwickler-Kolleginnen und -Kollegen müssen lediglich die Anweisung npm install ausführen, um sie in den node_modules-Ordner zu laden.

index.html

Die Startseite. Der Build-Prozess erweitert sie um Referenzen auf die generierten Bundles.

angular.json

Mit dieser Datei lässt sich das Verhalten der CLI anpassen. Beispielsweise referenziert sie globale Styles oder Skripte, die es einzubinden gilt.

Lassen Sie uns nun ein paar der Programmdateien unter src/app etwas genauer betrachten. Starten wir dabei mit der generierten AppComponent. Wie die meisten Angular-Komponenten besteht sie aus mehreren Dateien:

app.component.ts

TypeScript-Datei, die das Verhalten der Komponente definiert.

app.component.html

HTML-Datei mit der Struktur der Komponente.

app.component.scss

Datei mit lokalen Styles für die Komponente. Allgemeine Styles können in die besprochene styles.scss eingetragen werden.

Beispiel 1-1 zeigt den Inhalt der generierten app.component.ts:

Beispiel 1-1: Die generierte app.component.ts

import { Component } from '@angular/core';

@Component({

selector: 'app-root',

templateUrl: './app.component.html',

styleUrls: ['./app.component.scss']

})

export class AppComponent {

title = 'flight-app';

}

Es handelt sich dabei um eine Klasse, die lediglich eine Eigenschaft title vom Typ string besitzt. Letzteres muss hier gar nicht explizit angegeben werden: TypeScript kann sich diesen Umstand aus dem zugewiesenen Standardwert herleiten.

Die Angabe von export definiert, dass die Klasse auch in anderen Dateien der Anwendung genutzt werden darf.

Die Klasse wurde mit dem Dekorator Component versehen. Dekoratoren definieren Metadaten für Programmkonstrukte wie z.B. Klassen. Diesen importiert die Komponente in der ersten Zeile aus dem Paket @angular/core. Bei der Nutzung eines Dekorators wird ihm das Symbol @ vorangestellt.

Die Metadaten beinhalten den Selektor der Komponente. Das ist in der Regel der Name eines HTML-Elements, das die Komponente repräsentiert. Um die Komponente aufzurufen, können Sie also die folgende Schreibweise in einer HTML-Datei verwenden:

<app-root></app-root>

Der Dekorator verweist außerdem auf das HTML-Template der Komponente und ihre SCSS-Datei mit lokalen Styles. Letztere ist standardmäßig leer. Die HTML-Datei beinhaltet den Code für die oben betrachtete Startseite. Die ist zwar schön, enthält aber eine Menge HTML-Markup. Ersetzen Sie mal zum Ausprobieren den gesamten Inhalt dieser HTML-Datei durch folgendes Fragment:

<h1>{{title}}</h1>

Wenn Sie nun die Anwendung starten (ng serve -o), sollten Sie den Inhalt der Eigenschaft title als Überschrift sehen. Die beiden geschweiften Klammernpaare definieren eine sogenannte Datenbindung. Angular bindet also die angegebene Eigenschaft an die jeweilige Stelle im Template.

Mehr Informationen zu TypeScript, Datenbindungen und Angular im Allgemeinen finden Sie in den nächsten beiden Kapiteln. Um diesen Rundgang durch die generierten Programmdateien abzuschließen, möchten wir jedoch noch auf drei weitere generierte Dateien hinweisen. Eine davon ist die Datei app.module.ts, die ein Angular-Modul beinhaltet (siehe Beispiel 1-2).

Beispiel 1-2: Das generierte AppModule

import { BrowserModule } from '@angular/platform-browser';

import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';

@NgModule({

declarations: [

AppComponent

],

imports: [

BrowserModule

],

providers: [],

bootstrap: [AppComponent]

})

export class AppModule { }

Angular-Module sind Datenstrukturen, die zusammengehörige Building-Blocks wie Komponenten zusammenfassen. Technisch gesehen, handelt es sich dabei um eine weitere Klasse. Sie ist in den meisten Fällen leer und dient lediglich als Träger von Metadaten, die über den NgModule-Dekorator angegeben werden.

Lassen Sie uns einen Blick auf die Eigenschaften von NgModule werfen:

declarations

Definiert die Inhalte des Moduls. Derzeit beschränken sich diese auf unsere AppComponent. Sie wird in der dritten Zeile unter Angabe eines relativen Pfads, der auf die Datei app.component.ts verweist, importiert. Die Dateiendung .ts wird hierbei weggelassen.

imports

Importiert weitere Module. Das gezeigte Beispiel importiert lediglich das BrowserModule, das alles beinhaltet, um Angular im Browser auszuführen. Das ist auch der Standardfall.

providers

Hier könnte man sogenannte Services, die Logiken für mehrere Komponenten anbieten, registrieren. Kapitel 5 geht im Detail darauf ein.

bootstrap

Diese Eigenschaft verweist auf sämtliche Komponenten, die beim Start der Anwendung zu erzeugen sind. Häufig handelt es sich dabei lediglich um eine einzige Komponente. Diese sogenannte Root-Component repräsentiert die gesamte Anwendung und ruft dazu weitere Komponenten auf.

Das Modul, das die Root-Component bereitstellt, wird auch als Root-Module bezeichnet. Angular nimmt es beim Start der Anwendung entgegen und rendert die darin zu findende Root-Component. Für diese Aufgabe hat die CLI die Datei main.ts eingerichtet (siehe Beispiel 1-3).

Beispiel 1-3: Die generierte Datei main.ts

import { enableProdMode } from '@angular/core';

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';

import { environment } from './environments/environment';

if (environment.production) {

enableProdMode();

}

platformBrowserDynamic().bootstrapModule(AppModule)

.catch(err => console.error(err));

Die Funktion platformBrowserDynamic erzeugt eine sogenannte Plattform, die die Ausführung von Angular im Browser möglich macht. Andere Plattformen ermöglichen zum Beispiel die serverseitige Ausführung von Angular oder die Ausführung in mobilen Anwendungen. Die Nutzung im Browser ist jedoch der hier betrachtete Standardfall.

Die Methode bootstrapModule nimmt das Root-Modul entgegen, und Angular rendert daraufhin ihre Root-Component.

Die verwendete Eigenschaft environment.production informiert darüber, ob mit ng build ein Build für die Produktion angefordert wird oder mit ng serve eines fürs Debuggen. Wie oben erwähnt, veranlasst das die CLI, Optimierungen durchzuführen. Wir können aber auch innerhalb der Anwendung darauf reagieren: Hier wird dann zum Beispiel der Produktivmodus von Angular ebenfalls aktiviert. In diesem Modus ist Angular schneller, erzeugt aber auch weniger sowie weniger gut lesbare Fehlermeldungen.

Um festzulegen, wo auf der Seite unsere Root-Component darzustellen ist, ruft die ebenfalls generierte index.html sie auf:

<body>

<app-root></app-root>

</body>

Beim Build ergänzt die CLI diese index.html auch um Verweise auf die erzeugten Bundles. Eines davon beinhaltet den Code der Datei main.ts, die die Angular-Anwendung startet.

Internet Explorer 11

Bis Version 12 hat Angular Internet Explorer 11 unterstützt. Mit Version 12 wurde diese Unterstützung als veraltet (deprecated