Angular

Angular #

Struktur #

Eine basale Angular-Applikation besteht aus

  • HTML templates und zugehörige Komponentenklassen zu deren Steuerung,
  • Services für die Applikationslogik sowie
  • Module, um zusammengehörende Komponenten und Services zu isolieren

Then you launch the app by bootstrapping the root module. Angular takes over, presenting your application content in a browser and responding to user interactions according to the instructions you’ve provided.

Templates:

  • Layout mit HTML
  • Styling mit CSS
  • Angular-Markup
    • Event binding
    • Property binding

Modul:

  • @NgModule-Dekorator
File Purpose
app/app.component.ts Defines the same AppComponent as the one in the QuickStart playground. It is the root component of what will become a tree of nested components as the application evolves.
app/app.module.ts Defines AppModule, the root module that tells Angular how to assemble the application. Establishes key facts about the entire app for the Angular compiler.
main.ts Compiles the application with the JIT compiler and bootstraps the application’s main module (AppModule) to run in the browser. The JIT compiler is a reasonable choice during the development of most projects and it’s the only viable choice for a sample running in a live-coding environment like Plunker. You’ll learn about alternative compiling and deployment options later in the documentation.

Components #

The template, metadata, and component together describe a view. The architectural takeaway is that you must add metadata to your code so that Angular knows what to do. A component’s job is to enable the user experience and nothing more. It mediates between the view (rendered by the template) and the application logic (which often includes some notion of a model). A good component presents properties and methods for data binding. It delegates everything nontrivial to services.

Directives #

Directives sind Anweisungen zur Manipulation der DOM und lassen dynamische Templates zu. Eine Directive ist eine Klasse mit einem @Directive-Dekorator. Es lassen sich folgende Typen von Directives unterscheiden:

  • Components: Eine Direktive mit einem Template, wobei der @Component-Dekorator den @Directive-Dekorator mit Template-orientierten Features erweitert
  • Structural directives: Structural directives sind zuständig für das HTML-Layout. Sie gestalten oder modifizieren dazu die DOM durch Hinzufügen, Entfernen oder Manipulieren von Elementen. Beispiele:
    • *ngFor: <li *ngFor=„let hero of heroes“></li>
    • *ngIf: <hero-detail *ngIf=„selectedHero“></hero-detail>
  • Attribute directives: Verändern das Verhalten oder die Erscheinung eines DOM-Elements. Im Template sind sie syntaktisch identisch zu HTML-Attributen, daher der Name. Beispiel: ngModel: <input [(ngModel)]=„hero.name“>

Services #

Service ist eine breite Kategorie, welche Werte, Funktionen und Features umfasst, welche die Applikation benötigt. Fast alles kann also ein service sein. Normalerweise handelt es sich um eine Klasse mit einem engen, gut definierten Zweck.

Dependency Injection #

Zweck: Entkoppelung eines Objekts (Client) von denjenigen Objekten (Services), von denen es abhängig ist, so dass bei internen Änderungen der Services keine Anpassungen am Client notwendig sind.

Generelle Umsetzung: Die Abhängigkeiten eines Clients werden nicht im Client selbst erzeugt, sondern in einer zentralen Instanz (dem Injector). Der Injector versorgt die Instanz eines Clients mit den Abhängigkeiten, welche dieser benötigt.

Umsetzung in Angular:

In Angular sind Abhängigkeiten von Komponenten normalerweise Services. Damit Angular eine Komponente mit den benötigten Abhängigkeiten versorgen kann, müssen sie als Parameter des Konstruktors angegeben werden. Angular kann dann aus den Parametertypen die benötigten Services deduzieren. Dazu befragt es den Injector. Der Injector unterhält einen Container mit uniken Instanzen (Singletons) der injizierbaren Services. Ist noch keine Instanz des benötigten Services im Container erhalten, erstellt sie der Injector und fügt sie dem Container hinzu. Nachdem alle benötigten Abhängigkeiten aufgelöst und zurückgegeben wurden, wird der Konstruktor der Komponente von Angular aufgerufen.

Damit der Injector weiss, wie er eine Instanz eines benötigten Service erstellen kann, müssen diese registriert werden. Dazu wird der entsprechende Service im providers-Array des Decorators entweder des Moduls oder der Komponente aufgeführt. Bei letzterem wird immer dann eine neue Instanz des Services erstellt, wenn eine neue Instanz der Komponente kreiert wird, während bei Registrierung in @NgModule dieselbe Instanz des Services allen Komponenten der Applikation steht. Zudem muss der injizierbare Service den @Injectable()-Dekorator aufweisen, wenn dieser selber Parameter aufweist (es wird allerdings empfohlen, den Dekorator immer zu verwenden).

Providers #

Ein Provider ist ein „Rezept“, wie der Injector konfiguriert werden soll. Wie oben beschrieben, können Providers auf Ebene Komponente oder Ebene Modul definiert werden. Folgende Varianten sind möglich:

  • Als Provider-Klasse [ClassProvider]: providers: [Logger]; dies ist die Kurzform des Provider-Objektliterals [{provide: Logger, useClass: Logger}]
  • Dementsprechend kann für den gleichen Schlüssel auch ein anderer Service angegeben werden: [{provide: Logger, useClass: NewLogger}]
  • Alias [ExistingProvider]: [ NewLogger, { provide: OldLogger, useExisting: NewLogger}]
  • Value provider [ValueProvider], wobei die Instanz explizit und nicht durch den Injector (via @Injector-dekorierte Klasse) erstellt wird
  • Factory provider [FactoryProvider]:
    • Benötigt, wenn die Dependency dynamisch generiert werden soll, und die Dependency keinen unabhängigen Zugriff auf die der dynamischen Generierung zugrundeliegenden Informationen (bspw. ein Flag) hat
    • Beispiel: Gewisse Daten, die die Dependency bereitstellt, dürfen nur von authenifizierten Nutzern eingesehen werden. Der Status der Authentifizierung kann sich während einer Session ändern.
    • Die Idee ist, dass eine Factory-Funktion Zugriff auf die benötigten Informationen hat (indem sie durch Parameter übergeben werden), und auf dieser Grundlage die Dependency erstellen kann.
    • Im Provider werden schliesslich die zu erstellende Dependency, die Factory-Funktion sowie die von der Factory-Funktion benötigten Dependencies übergeben. Bsp.: { provide: HeroService, useFactory: heroServiceFactory, deps: [Logger, UserService] }

Dependency injection tokens #

  • Da Interfaces nur von Typescript verwendet werden und bei der Transpilierung entfernt werden, können sie auch nicht als DI-Tokens verwendet werden. Dies führt zu einem potentiellen Problem, wenn die Dependency keine Klasse, sondern beispielsweise ein Objektliteral ist.
  • Eine Möglichkeit ist die Verwendung eines InjectionToken. Der Typ der Dependency wid dabei als (ansonsten optionaler) Typparameter übergeben
  • @Optiona(): Dekorator, um eine Dependency als optional zu deklarieren.

Templates #

Data binding #

Vier Richtung des Data binding:

  • Interpolation: Ein Wert wird in einer Component-Klasse definiert und im Template verwendet
  • Property Binding: Eine Eigenschaft der View wird definiert
  • Event Binding: Bindet einen Event an eine Methode, welche in der Component definiert wird
  • Two-way Data Binding: Kombiniert property und event binding

Data binding ist auch wichtig für die Kommunikation zwischen Eltern- und Kinder-Komponenten

Template expressions #

A template expression produces a value. Angular executes the expression and assigns it to a property of a binding target; the target might be an HTML element, a component, or a directive.

Sie kommen zur Anwendung in Interpolations (in den doppelten geschweiften Klammern) und in Property bindings (rechts des Zuweisungsoperators in Apostrophen).

Grundsätzlich ist jeder JavaScript-Code valide, solange die verwendeten Operatoren keine Seiteneffekte erzeugen oder solche vereinfachen (z.B. ++, , new, =). Zudem führen sie zwei neue Operatoren (Template expression operators) ein, | und ?.

The expression context is typically the component instance. An expression may also refer to properties of the template’s context such as a template input variable (let hero) or a template reference variable (#heroInput).

The context for terms in an expression is a blend of the template variables, the directive’s context object (if it has one), and the component’s members. If you reference a name that belongs to more than one of these namespaces, the template variable name takes precedence, followed by a name in the directive’s context, and, lastly, the component’s member names.

Guidelines for template expressions:

  • No side effects
  • Quick execution
  • Simplicity
  • Idempotence (Referential transparency)

Template statement #

A template statement responds to an event raised by a binding target such as an element, component, or directive. You’ll see template statements in the event binding section, appearing in quotes to the right of the = symbol as in (event)=„statement“. A template statement has a side effect. That’s the whole point of an event. It’s how you update application state from user action.

Observable #

An Observable is a stream of events that you can process with array-like operators.

Angular core has basic support for observables. Developers augment that support with operators and extensions from the RxJS library. You’ll see how shortly.

The *ngFor can’t do anything with an Observable until you route it through the async pipe (AsyncPipe). The async pipe subscribes to the Observable and produces the array of heroes to *ngFor. private searchTerms = new Subject(); // Push a search term into the observable stream. search(term: string): void { this.searchTerms.next(term); }

A Subject is a producer of an observable event stream; searchTerms produces an Observable of strings, the filter criteria for the name search.

Each call to search() puts a new string into this subject’s observable stream by calling next().

Routing #

Die Abfolge im Router-Array ist entscheidend: Spezifischere Routes müssen immer vor allgemeineren Routes deklariert werden. Generell gilt die Abfolge:

  • Routes mit einem statischen Pfad
  • Route mit einem leeren Pfad
  • Wildcard-Route (**) zuletzt

Routing-Events #

Während der Navigation auf eine Route werden verschiedene Events ausgelöst, die mit router.events.subscribe() beobachtet werden können:

Formulare #

Angular kennt zwei verschiedene Interaktionsarten mit Formularen: template-driven und reactive.

template-driven reactive
Programmlogik Im Template der Komponente. Template definiert Formularstruktur, Format der Felder und Validierungsregeln. Im (TypeScript-)Code. Template wird entweder statisch definiert oder auf Grundlage des Models dynamisch erzeugt.
Modul FormsModule ReactiveFormsModule
Modell Implizit erzeugt (durch die Directives NgModel, NgModelGroup und NgForm, welche den Formularelementen hinzugefügt werden) Muss explizit erzeugt werden, indem die Klassen FormControl, FormGroup und FormArray instanziiert werden.
Anwendungsfall Einfache Formulare, da auf HTML-Syntax limitiert. Komplexe Formulare, da Datenstruktur via Code definiert werden kann.
Testbar Nur mit Webbrowser Unit-Testing in IDE möglich.

Debugging #

Debugging in Chromium #

Tools #

Guides #

Debugging in Firefox (Developer Edition) #

Tools #

Guides #

Debugging in Webstorm (mit Chrome / Chromium) #

Tools #

Guides #