Angular 16.2: Applikationshooks und Bindings für dynamische Komponenten

Neben vielen kleineren Verbesserungen stechen in dem Minor Release Angular 16.2 vor allem zwei neue Features hervor.

In Pocket speichern vorlesen Druckansicht 2 Kommentare lesen

(Bild: Shutterstock)

Lesezeit: 4 Min.
Von
  • Rainer Hahnekamp
Inhaltsverzeichnis

Das Angular-Team hat Version 16.2 veröffentlicht und führt darin unter anderem zwei neue Features ein. Zum einen vereinfacht das Release Bindings für dynamische Komponenten und zum anderen bringt es die neuen Applikationshooks afterRender und afterNextRender.

Die Direktive NgComponentOutlet lädt Komponenten dynamisch. Sie fungiert als Platzhalter und kann erst zur Laufzeit entscheiden, welche Komponente überhaupt verwendet werden soll. Bis dato war diese Direktive jedoch mit Einschränkungen versehen. So konnte man nicht auf einfache Art und Weise Property Binding auf die dynamische Komponente anwenden. In Angular ist Property Binding der Vorgang, bei dem Elternkomponenten ihren Kindern Daten übergeben können.

Im folgenden Codebeispiel gibt es zwei unterschiedliche Komponenten, die die AppComponent je nach Tageszeit verwendet. Beide Komponenten benötigen denselben Input.

Mit Angular 16.2 sieht der Code nun wesentlich einfacher aus:

@Component({
  selector: 'app-root',
  template: `<ng-container
    *ngComponentOutlet="component; inputs: context"
  ></ng-container>`,
  standalone: true,
  imports: [NgComponentOutlet],
})
export class AppComponent {
  daylightService = inject(DaylightService);
  userService = inject(UserService);
  component;
  context: Record<string, unknown> = {};

  constructor() {
    this.component = this.daylightService.isDay()
      ? WelcomeAtDayComponent
      : WelcomeAtNightComponent;
    const { sunrise, sunset } = this.daylightService.getSunTimes();
   
    this.context = {
      username: this.userService.username,
      sunrise,
      sunset,
    };
  }
}

Die Property component bekommt je nach Rückgabewert von isDay() des daylightService entweder die Klasse der WelcomeAtDayComponent oder WelcomeAtNightComponent.

Ferner enthält context die Werte für das Property Binding der beiden Komponenten.

Im Template findet schlussendlich der Einsatz statt. *ngComponentOutlet lädt in Kombination mit inputs die dynamische Komponente und führt intern das Property Binding durch.

Ein weiteres interessantes Feature sind die neuen Applikationshooks afterRender und afterNextRender.

Bis dato kannte man Hooks in Angular nur auf Komponentenebene. Das sind Interfaces, die die Komponenten implementieren können. Bekannte Beispiele sind OnInit oder OnDestroy.

Die neuen Hooks beziehen sich nicht mehr auf die Komponente. Sie sind auch keine Interfaces, sondern normale Funktionsaufrufe. Dadurch eignen sie sich auch zur Verwendung in Services. Dabei ist wichtig, dass sie in dem sogenannten Injection Context laufen. In Angular ist das hauptsächlich der Code, der bei der Instanziierung ausgeführt wird. Methoden, die nur im Injection Context gültig sind, sind nicht Neuland in Angular. Für inject oder effect (Signale) gelten bereits dieselben Regeln.

Angular registriert alle Aufrufe von afterRender und afterNextRender und führt sie dann in derselben Reihenfolge aus, wie sie registriert wurden. afterRender läuft dabei nach jedem abgeschlossenen Change-Detection-Zyklus. Das ist die Funktion, bei der Angular über den Komponentenbaum traversiert und bei neuem State das DOM entsprechend aktualisiert.

Angular führt afterNextRender auch nach einem Durchlauf der Change Detection aus, im Gegensatz zu afterRender jedoch nur ein einziges Mal. Vielleicht wäre hier die Bezeichnung afterOneRender treffender gewesen.

afterNextRender eignet sich, wenn eine Drittbibliothek ein gerendertes DOM-Element benötigt. afterNext wird hingegen eher in Bibliotheken seinen Einsatz finden, wo man mit dem Framework mehr auf "Tuchfühlung" gehen muss.

Beide Applikationshooks laufen ausschließlich im Browser und nicht auf dem Server, falls Server-Side Rendering im Einsatz ist.

Der folgende Code zeigt beide Hooks im Einsatz.

@Component({
  selector: 'app-root',
  template: ` <img
    src="https://api.eternal-holidays.net/holiday/darmstadt.jpg"
  />`,
  standalone: true,
})
export class AppComponent {
  ngZone = inject(NgZone);
  cdCounter = 0;

  constructor() {
    afterRender(() => {
      console.log('CD Runs: ', ++this.cdCounter);
    });

    afterNextRender(() => {
      this.ngZone.runOutsideAngular(() => {
        const img = document.getElementsByTagName('img')[0] as HTMLImageElement;

        img.addEventListener('load', () => {
          if (img.naturalWidth > img.width) {
            console.error('image too large. consider NgOptimizedImage');
          }
        });
      });
    });
  }
}

afterRender erhöht bei jedem Durchlauf den internen Zähler. Der Anwendungsfall ist hier eindeutig Analyse beziehungsweise Debugging.

afterNextRender registriert sich hingegen auf das load-Event des gerenderten Bildes und überprüft, ob die Dimensionen des Originals mit denen der Darstellung übereinstimmen.

Zusätzlich gibt es noch eine Reihe weiterer kleiner Features und natürlich auch Bugfixes im neuen Release. Nicht unerwähnt sollen die Arbeiten am Server-Side Rendering sein. Angular 16.2 bringt vor allem im Bereich des CLI einige Verbesserungen mit sich.

Für November ist das Release von Angular 17 geplant. Nach aktuellem Stand müssen sich Entwicklerinnen und Entwickler jedoch für die angekündigte Signalkomponente bis Angular 18 gedulden. Allerdings wird in Angular 17 die aktuelle Signalfunktionalität den Developer-Preview-Status verlassen und stabil werden.

Vor zwei Wochen endeten überdies RFCs (Request for Comments), die die Templatesyntax um Kontrollstrukturen erweitern werden. Daneben plant das Angular-Team ein sogenanntes "deferred loading" von Komponenten. Dabei wird eine Komponente erst vom Server geladen, wenn sie zum Beispiel in den Viewport kommt.

Inwiefern sich diese neuen Features bereits in Version 17 verwenden lassen, bleibt offen. Auf jeden Fall setzt das Angular-Framework seine Innovation ungehemmt fort.

Der Beispielcode befindet sich zum Ausprobieren auf GitHub. Dort finden sich auch die Release Notes zu Angular 16.2.

(mai)