Suche
Das ist neu in Angular 4

Angular 4 – das Update: Diese Features müssen Sie kennen

Karsten Sitterberg, Thomas Kruse

(c) Shutterstock / dencg

Endlich ist es soweit: Angular 4 ist in der finalen Version erschienen. Karsten Sitterberg und Thomas Kruse erklären alle Neuerungen, geben Tipps zur Migration und wagen einen Ausblick auf Angular 5.

Angular 4 – das Update

Rund ein halbes Jahr nach der Veröffentlichung von Angular 2 steht das nächste große Update an: Angular 4, oder besser gesagt Angular v4. Denn ab jetzt, so hat sich das Team entschieden, soll es “just Angular” heißen und die Versionsnummer nicht mehr expliziter Bestandteil des Namens sein. Ursprünglich diente die “2” zur Differenzierung zwischen AngularJS und dem völlig neu entwickelten Angular Framework, da viele Konzepte überdacht oder verfeinert wurden. So kann Angular zum Beispiel in Dart, TypeScript und ECMA 5 genutzt werden.

Zum Zeitpunkt der Veröffentlichung von Angular 2 wurde bereits festgelegt, wie zukünftige Versionen angegeben werden sollen: Es soll dem “semantic versioning” entsprechend vorgegangen werden. Das bedeutet, dass auf einen Blick erkennbar ist, wie sich eine Version zu einer anderen in Bezug auf Kompatibilität und neue Features verhält.

Die Versionsnummern werden damit nach dem Schema MAJOR.MINOR.PATCH aufgebaut. Die jeweilige Stelle wird nach den folgenden Kriterien verändert:

  1. MAJOR wird dann erhöht, wenn es eine inkompatible Änderung der API gibt. Bei Angular kann dies zum Beispiel die Nutzung einer neueren Version einer der genutzten Bibliotheken wie zone.js oder reactJS sein, die eine geänderte API aufweist.
  2. MINOR wird dann erhöht, wenn eine zusätzliche Funktionalität bereitgestellt wird, bestehende Funktionen und die API jedoch stabil gehalten werden. Dies könnte bei Angular z.B. eine zusätzliche Pipe sein, die als Teil des Frameworks ausgeliefert wird.
  3. PATCH wird erhöht, wenn eine Fehlerbehebung vorgenommen wird, die die API nicht verändert und somit rückwärtskompatibel ist.
Semantic Versioning in Angular 4

Semantic Versioning in Angular 4

Ergänzend gibt es noch einen optionalen -QUALIFIER, der eine Version näher bezeichnet. Beispielsweise 4.0.0-rc.1 oder 4.0.0-beta, um eine Beta-Version oder einen Release-Kandidaten auszuzeichnen.

Sprung: Von 2 zu 4 – als nächstes 8?

Manch einer wird sich gewundert haben, dass die nächste Version nach Angular 2 nicht Angular 3 sondern “Angular” v4 wird. Der Hintergrund ist, dass eine Harmonisierung der Versionsnummern aller Bestandteile von Angular angestrebt wurde. Der Angular eigene Router wurde jedoch bereits in Version 3 entwickelt und muss nun auf Version 4 gehoben werden. Zur Vereinheitlichung wurde daher Version 4 für das gesamte Angular Framework gewählt. Lediglich Angular CLI, das Kommandozeilenwerkzeug zur Projekterstellung und Abstraktion von Build- und Testausführung, liegt dann in Version 1.0.0 vor.

Das ist neu in Angular 4

Grund für die neue Major-Version sind sowohl neue Features als auch zur bisherigen Version inkompatible Änderungen. Werfen wir als erstes einen Blick auf die neuen Features:

Router ParamMap

Beim Router ist es ab Version 4 möglich, die einer Route zugeordneten Route- und Queryparameter als sogenannte ParamMap abzufragen.

Bisher lagen die Route-Parameter in einer einfachen Key-Value-Objektstruktur vor, sodass man über die typische JavaScript-Syntax (parameterObjekt[‘parameter-name’] ) auf sie zugreifen konnte.

class MyComponent {
 sessionId: Observable<string>;

 constructor(private route: ActivatedRoute) {}

 ngOnInit() {
   this.sessionId = this.route
     .queryParams
     .map(params => params['session_id'] || 'None');
 }
}

Jetzt sind die Parameter ebenfalls als Map verfügbar, sodass man die Parameter als einfache Methodenaufrufe ausführen kann (parameterMap.get(‘parameter-name’)).

class MyComponent {
 sessionId: Observable<string>;

 constructor(private route: ActivatedRoute) {}

 ngOnInit() {
   this.sessionId = this.route
     .queryParamMap
     .map(paramMap => paramMap.get('session_id') || 'None');
 }
}

 

Die Verwendung als Map bringt auch Vorteile in Sachen Typsicherheit. Die alte Key-Value Struktur hatte einen unsicheren Typ (type Params = {[key: string]: any}), wodurch der Parameter-Wert alle möglichen Typen haben konnte. Bei der neuen Map ist es jedoch nun so, dass der Parameter-Wert – abhängig von der genutzten Methode – entweder ein String oder ein Array-of-String ist. Es gelten die Typdefinition für einzelne Parameter-Werte, ParamMap.get(): string und die Typdefinition für mehrere Werte ParamMap.getAll(): string[].

Animationen

Bisher stellte Angular die für Animationen notwendigen Funktionen als Teil des @angular/core Moduls bereit. Damit wurden diese Code-Teile auch dann Bestandteil der Anwendung, wenn diese gar nicht benötigt wurden, weil die Anwendung keinen Gebrauch von Animationen macht. Um unnötig große Bundles zu vermeiden, wurde dieser Teil nun in ein eigenes Paket ausgegliedert. (Damit handelt es sich nicht nur um ein neues Feature, sondern auch um eine Änderung, die Anpassungen bei bisherigen Anwendungen erforderlich macht, sofern diese Animationen verwenden.)

Zukünftig werden die Animationen über das Modul BrowserAnimationsModule aus @angular/platform-browser/animations bereitgestellt.

ngIf: Jetzt auch mit “else”

Häufig kommt es vor, dass in Templates sogenanntes “conditional rendering” genutzt wird, um in Abhängigkeit von einer Bedingung Informationen anzuzeigen. Dazu wird *ngIf verwendet. Ist die Bedingung nicht erfüllt, wird das Element und alle Kindelemente nicht in den DOM-Baum eingehängt. In vielen Fällen wird auch der komplementäre Fall benötigt, dazu musste bisher die Bedingung umgekehrt formuliert werden, und ein weiteres *ngIf wurde verwendet.

Darunter leidet die Lesbarkeit des Codes und auch die Wartbarkeit, schließlich sind bei Anpassungen mehrere Stellen zu berücksichtigen.

Mit Angular 4 ist jetzt auch ein else verfügbar, um diesem Anwendungsfall gerecht zu werden. Anders als vielleicht erwartet, nutzt Angular dabei ein separat referenziertes Template-Fragment, das im alternativen Fall an die Stelle des Elements, das mit dem *ngIf ausgezeichnet ist, eingesetzt wird.

Zur Veranschaulichung dient ein Beispiel, bei dem in Abhängigkeit davon, ob ein User angemeldet ist, sein Name oder ein “Anmelden” Link angezeigt werden soll. Erst in der alten Syntax:

<p *ngIf="isAuthenticated">Eingeloggt als auth.username</p>
<p *ngIf="!isAuthenticated">Bitte anmelden: <button>Login</button></p>

In der neuen Syntax

<ng-template #needsLogin>
  <p>Bitte anmelden: <button>Login</button></p>
</ng-template>
<p *ngIf="isAuthenticated; else needsLogin">
  Eingeloggt als auth.username
</p>

 

Im Zusammenspiel mit der async-Pipe bietet *ngIf jetzt auch verbesserte Funktionalität beim reaktiven Programmieren. Bisher gab es schon die Möglichkeit, sich per async-Pipe auf Asynchrone Objekte wie Observables und dergleichen aus dem Template heraus zu „subscriben“ (bzw. „unsubscriben“). Mit der neuen *ngIf-Syntax ist es nämlich nun möglich, eine lokale Template-Variable an das Resultat des If-Ausdruckes zu hängen. Im unten stehenden Beispiel wird etwa das Observable, welches in der Variable auth steckt, durch die async-Pipe aufgelöst. Das Resultat dieser Auflösung kann dann mit Hilfe der Variable user innerhalb des Template genutzt werden.

<ng-template #loading>
  <p>Lade Nutzerdaten...</p>
</ng-template>
<p *ngIf="auth | async; else loading; let user">
  {{user.username }}
</p>

 

Es sei noch darauf hingewiesen, dass die async-Pipe keine zwingende Voraussetzung zur Nutzung der neuen Syntax ist, sondern in diesem Beispiel nur zur Veranschaulichung gewählt wurde. Es kann auch jede andere Pipe oder auch gar keine Pipe verwendet werden.

Mehr zum Thema: TypeScript, Angular, NetBeans IDE: Ein unschlagbares Trio

Dynamische Komponenten mit NgComponentOutlet

Mit der neuen *ngComponentOutlet-Direktive ist es möglich, dynamische Komponenten auf deklarativem Weg zu erzeugen. Bisher war es relativ aufwendig, dynamisch zur Laufzeit Komponenten zu erzeugen und darzustellen, denn es ist nicht damit getan, etwas HTML-Code zu schreiben. Angular muss nämlich von der Komponente wissen und diese sowohl in den Lifecycle einbinden, als sich auch um Databinding und Change Detection kümmern. Deshalb ging der bisherige Weg, die ComponentFactory zu nutzen, was mit relativ viel Programmieraufwand einher.

Das folgende Code Beispiel zeigt, wie es die Umsetzung mit dem *ngComponentOutlet aussieht:

@Component({
  selector: ‘app-first-time-visitor’,
  template: ‘<h1>Welcome to our Page!</h1>’,
})
export class FirstTimeVisitorComponent {}
@Component({
  selector: ‘app-frequent-visitor’,
  template: ‘<h1>Welcome Back!</h1>’,
})
export class FrequentVisitorComponent {}
@Component({
  selector: ‘app-root',
  template: `
        <h1>Hello Angular v4!</h1>
        <ng-container *ngComponentOutlet="welcome"></ng-container>
  `,
})
export class App implements OnInit{
  welcome = FirstTimeVisitorComponent;
 
  ngOnInit() {
    if(!this.user.isfirstVisit){
      this.alert = FrequentVisitorComponent;
    }
  }
}

In diesem Beispiel wird, je nachdem, ob der User das erste Mal auf die Seite kommt oder schon öfter auf der Seite war, entweder die FirstTimeVisitorComponent oder die FrequentVisitorComponent zur Begrüßung des Users verwendet. Dabei wird im OnInit-Lifecycle-Hook überprüft, ob der Besuch des User sein erster ist. Basierend darauf wird dann dynamisch eine andere Komponente in das Template zur Darstellung übergeben.

Mehr zum Thema: Angular Tutorial: Rascher Projektstart mit dem Angular CLI

TypeScript 2.1/2.2

Mit der offiziellen Unterstützung der neueren TypeScript-Versionen wird die Typsicherheit von Angular-Anwendungen und die Geschwindigkeit den ngc-Compilers erhöht.

StrictNullChecks

Ein Teil der verbesserten Type Checks konnte leider erst einmal nicht in Angular 4 aufgenommen werden, da sich in der RC-Phase Inkompatibilitäten herausgestellt haben. Dieses Feature ist nun für v4.1 geplant.

Angular Universal

Angular Universal bietet die Möglichkeit, Angular-Anwendungen auch außerhalb des Webbrowsers zu rendern, zum Beispiel direkt auf einem Webserver. Damit lassen sich suchmaschinenfreundliche Webseiten erstellen, da kein JavaScript zur Darstellung der Inhalte erforderlich ist. Ein anderer Anwendungsfalls ist die Nutzung von WebWorker Threads, um außerhalb des GUI Threads Inhalte zu rendern, die dann lediglich zur Darstellung in den DOM Tree eingehängt werden müssen.

Für Java-Entwickler interessant dürften die Tickets zur Unterstützung des Spring Frameworks bzw. Spring Boot sein, um mittels Nashorn oder J2V8 serverseitig zu rendern:

Leider sind noch keine produktiv einsetzbaren Ergebnisse verfügbar. Mittels node-Runtime lässt sich schon jetzt Angular Universal aus verschiedenen Sprachen heraus nutzen.

Neue Pipe: Title Case

Mit der neuen titlecase-Pipe werden jeweils die ersten Buchstaben eines Wortes zu Großbuchstaben gewandelt, alle anderen Buchstaben werden Kleinbuchstaben.

Formulare erhalten automatisch ‘novalidate’

Bisher mussten Formulare durch ‘novalidate’ ausgezeichnet werden, wenn die durch HTML5 spezifizierte Validierung durch den Browser unterdrückt werden sollte, um der Angular-Anwendung die volle Kontrolle zu ermöglichen.

Das führte dazu, dass Entwickler regelmäßig jedes Formular mit “novalidate” ausgezeichnet haben. In Angular 4 wird dies Attribut automatisch gesetzt.

Source Maps auch für Templates

Wenn es um das Debugging und die Fehlersuche geht, sind Source-Maps unerlässlich. Damit lässt sich der Bezug zwischen Quellcode und Ergebnis herstellen, um die genaue Fehlerstelle einzukreisen. Der neue Template Compiler erzeugt nun auch für die Templates Source-Maps, so dass sowohl im Browser Debugger als auch bei Crash-Reports und Logmeldungen bessere Kontextinformationen zur Verfügung stehen.

Flache ES-Module (Flat ESM / FESM)

Statt vieler kleiner Files, die zu einem Modul gehören, werden nun auch “flache” Versionen der Module ausgeliefert. Flach bedeutet in diesem Fall, dass pro Modul ein File ausgeliefert wird, in dem sich dann alles zum Modul gehörige befindet. Diese flachen Module sollen zu einer besseren Performance sowohl beim Kompilieren als auch beim Ausführen im Browser führen. Weiterhin sollen dadurch das Treeshaking und der Build verbessert werden und somit letzten Endes die Anwendungen kleiner werden können.

Neue View Engine für überragende Geschwindigkeit

Angular generiert aus Templates und den @Component-Elementen die View-Schicht. Dabei gibt es den Just-In-Time Compiler (JIT), der vor allem während der Entwicklung eingesetzt wird und im Wesentlichen ein Interpreter ist. Parallel dazu existiert der Ahead-of-Time Compiler (AoT), der aus den Templates und Komponenten ausführbaren (JavaScript-)Code mit eingebetteten HTML-Fragmenten erzeugt. Dieser oft auch Codegen genannte Schritt erzeugt relativ viel Code: Event-Handling, Change-Detection, Data-Binding und Umgang mit dem dynamischen Verhalten der Komponenten werden hier in das Ergebnis hineingewoben.

Die so erzeugten Anwendungen weisen eine sehr hohe Geschwindigkeit auf, doch ist der Umfang des Codes beträchtlich. Darunter leidet dann die Startgeschwindigkeit einer Anwendung, schließlich muss der ganze erzeugte Code auch heruntergeladen werden.

Das Angular-Team zeigt auch hier wieder eine sehr offenen Herangehensweise und nimmt sich z.B. das Inferno.js Framework als Referenz für die Performance und Designentscheidungen andere Frameworks. Die verschiedenen Anforderungen, Ziele und Ansätze an die Template-Schicht von Angular werden auch in dem umfangreichen Designdokument zur View Engine diskutiert.

Im Ergebnis liefert Angular 4 deutlich kleinere Templates, wodurch sich sowohl die Ladezeit reduziert, als auch die Gesamtgeschwindigkeit durch die reduzierte Menge an Code erhöht. Im Mittel kann man von ca 60% Ersparnis ausgehen, was gerade für mobile Anwendungen eine signifikante Verbesserung darstellt.

Zusätzlich konnte die dabei anfallende Arbeit für den Garbage Collector im Browser reduziert werden, was sich ebenfalls durch eine insgesamt verbesserte Performance zeigt. Der erzeugte Code eignet sich dabei nicht nur gut, um mit klassischen Verfahren wie gzip komprimiert zu werden, sondern lässt sich mit dem Google Closure Compiler auch hervorragend minifizieren, was den Umfang weiter reduziert.

Erforderliche Anpassungen für Angular 4

Werfen wir einen Blick darauf, welche Anpassungen an bestehenden Projekten für Angular 4 notwendig sind. Um Entwicklern zukünftig Migrationen möglichst leicht zu machen, wird ein interaktiver Leitfaden durch das Angular Team bereitgestellt: https://angular-update-guide.firebaseapp.com/. Aktuell ist das Projekt noch in einem sehr frühen Stadium und gibt inkonsistente oder veraltete Ratschläge, so dass von einer Nutzung zum jetzigen Zeitpunkt noch abzuraten ist.

Update der Dependencies

Per npm können die Versionen der Angular-Module aktualisiert werden:

npm install @angular/{common,compiler,compiler-cli,core,forms,http,platform-browser,platform-browser-dynamic,platform-server,router,animations}@next –save

Geänderte Lifecycle Events

Klassen dürfen keine Lifecycle Events über Vererbung implementieren, sondern müssen Interfaces verwenden:

Foo extends OnInit

wird zu:

Foo implements OnInit

Diese Änderung dürfte wenige Entwickler betreffen und ist auch einfach umzusetzen.

Template-Tag-Umbenennung

Bisher wurde <template> als Tag bzw. Attribut für Templates verwendet. Dies ist nun als deprecated markiert. Es wird ersetzt durch <ng-template>.

Zugriff auf Renderer

Bisher konnte Renderer bzw. RootRenderer genutzt werden. Dies ist nun nicht mehr möglich. Der Zugriff erfolgt nun über RendererFactory2.

Verwendung von Animationen

Bisher waren Animationen Teil von Angular core. Durch die Separierung in Angular 4 müssen bei Verwendung von Animationen die Imports angepasst werden:

import {Component, OnInit} from '@angular/core';
import {
  animate,
  state,
  style,
  transition,
  trigger } from '@angular/animations'

 

Während im Beispiel Component und OnInit weiter aus Angular Core kommen, werden “animate”, “state”, “style”, “transition” und “trigger” nun aus Angular Animations importiert.

Neues in Angular CLI

Anglar CLI ist das Kommandozeilenwerkzeug, um Angular-Projekte komfortabel erstellen, bauen und testen zu können. Zusammen mit Angular 4 wurde Angular CLI in Version 1.0.0 veröffentlicht und ist nun Kernbestandteil des Angular-Projekts.

Als besonders erwähnenswertes Feature dürfte die Unterstützung alternativer Paketmanager zu npm sein: Es werden etwa auch Facebook yarn und cnpm unterstützt. Welche Vorteile yarn gerade für Angular-Anwendungen bietet, kann man hier nachlesen:

Angular 2 und Yarn: Kein Seemannsgarn

 

Die Verwendung von yarn lässt sich folgendermaßen aktivieren:

ng set –global packageManager=yarn

Als weitere Neuerung erstellt Angular CLI in Version 1.0.0 nun standardmäßig Angular-4-Projekte und liefert bessere Fehlermeldungen bei AoT-Kompilierung von Templates.

Ausblick: Angular 5 und die Zukunft

Die Welt entwickelt sich weiter und Angular hält Schritt: Auch für die Zukunft sind regelmäßig neue Releases geplant.

Derzeit wird an einem Modul für ServiceWorker gearbeitet, um darüber z.B. Push-Benachrichtigungen in Angular abbilden zu können.

Aktuell sieht die Zeitplanung so aus, dass alle sechs Monate eine neue Major-Version von Angular veröffentlicht wird. Damit steht Angular 5 für ca. Oktober diesen Jahres auf der Agenda, März 2018 folgt Angular 6. Dazwischen wird es, wie auch schon seit Veröffentlichung von Version 2.0, Minor-Releases und, falls erforderlich, Bugfixes geben. Darüber hinaus hat sich das Team entschlossen, zeitbasierte Releases zu machen:

  • Jede Woche ein Patch/Bugfix Release
  • Jeden Monat ein Minor Release
  • Alle sechs Monate ein Major Release, wobei auf eine einfache Migration von der Vorgängerversion großer Wert gelegt wird.

Wichtig ist dabei zu beachten, dass Features, die als “deprecated” markiert werden, im nächsten Release entfernt werden. Damit hat man als Entwickler ein Zeitfenster von guten sechs Monaten, um eine Migration vorzunehmen, wenn direkt auf die nächste Major-Version aktualisiert werden soll. Das ist auch empfehlenswert, denn ein “Migrationsstau” führt auf kurz oder lang dazu, dass man auf einer alten Version festhängt und der Aufwand deutlich steigt, wenn eine Migration mit einem Sprung über mehrere Versionen ansteht.

Durch Community-Feedback ist dem Angular-Team klar, dass gerade in Enterprise-Umgebungen die Entwicklungsgeschwindigkeit von Angular als “sehr schnell” empfunden wird. Um den besonderen Bedürfnissen großer Organisationen gerecht zu werden, gibt es Überlegungen, auch eine Long-Term-Support (LTS) Version von Angular anzubieten, die über einen längeren Zeitraum von Bugfixes profitiert.

Das mag den einen oder anderen Projektleiter beruhigen, spannend dürfte dabei sein, wie sich die Migration von einer LTS- zur nächsten LTS-Version gestaltet. Erfahrungsgemäß ist es vorteilhaft, sich kontinuierlich um Aktualität zu bemühen und von den aktuellen Entwicklungen zu profitieren. Wie lang genau der LTS-Zeitraum für Angular und AngularJS sein soll, wird derzeit noch diskutiert.

Google nutzt intern ein Werkzeug zur automatischen Code-Migration. Auch hier ist im Gespräch, das Tool der Öffentlichkeit zur Verfügung zu stellen oder ein vergleichbares Werkzeug zur automatisierten Migration bereitzustellen.

An den Entwicklungen lässt sich sehen, dass es Angular – auch dank dem sehr offenen Ohr für die Wünsche der Community – schafft, als erwachsenes und professionelles Framework sowohl für den Einsatz in kleinen agilen Teams als auch in großen Organisationen aufzutreten.

Lesetipp:

Angular 4 ist da – das ist neu

Geschrieben von
Karsten Sitterberg
Karsten Sitterberg
Karsten Sitterberg ist als freiberuflicher Entwickler, Trainer und Berater für Java und Webtechnologien tätig. Karsten ist Physiker (MSc) und Oracle-zertifizierter Java Developer. Seit 2012 arbeitet er mit trion zusammen.
Thomas Kruse
Thomas Kruse
Thomas Kruse hat Informatik studiert und ist als Architekt, Berater und Coach für die trion development GmbH tätig. In seiner Freizeit engagiert er sich im OpenSource Umfeld und leitet die Java Usergroup in Münster.
Kommentare
  1. Christian2017-03-24 15:39:15

    Vielen Dank für diesen sehr informativen Artikel!

  2. Smith2017-03-25 18:26:49

    Mein Herz schlägt für VueJS <3

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.