Zurück zur Startseite

Reine Funktionen in Angular-Vorlagen 21.2

Seit Version 21.2 unterstützt Angular reine JS-Funktionen in Vorlagen für Filterung, Suche und Aktualisierung von Signals ohne Komponentenmethoden. Zerlegung von Navigation, Sortierung, Übergabe von Funktionen via input-Beispiele. Einschränkungen: Verbot mehrzeiliger Ausdrücke und Pipes in Funktionen.

Funktionen in Angular-Vorlagen: Filterung und Sortierung ohne Klassen
Advertisement 728x90

Reine Funktionen in Angular 21.2 Templates: Möglichkeiten und Grenzen

Ab Version 21.2 erlaubt Angular die direkte Verwendung reiner JavaScript-Funktionen in HTML-Templates, ohne Methoden in der Komponentenklasse deklarieren zu müssen. Dies vereinfacht die Datenverarbeitung wie Array-Filterung oder Berechnungen basierend auf Signals, erfordert jedoch strikte Einhaltung der Regeln für reine Funktionen.

Betrachten Sie eine Komponente mit einer Heldenliste, wobei die Daten in einem heroes-Signal vom Typ WritableSignal<Hero[]> gespeichert sind:

import { Component, signal, WritableSignal } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HeroesList } from '../heroes-list/heroes-list';

export interface Hero {
  id: number;
  name: string;
  lastName: string;
  nickname: string;
  email: string;
}

@Component({
  selector: 'app-heroes',
  imports: [HeroesList, CommonModule],
  templateUrl: './heroes.component.html',
  styleUrl: './heroes.component.scss',
  standalone: true
})
export class HeroesComponent {
  heroes: WritableSignal<Hero[]> = signal<Hero[]>([
    // Heldendaten
  ]);

  selectedHeroId: WritableSignal<number> = signal<number>(1);
}

Grundlegende Listenausgabe über @for:

Google AdInline article slot
<ul>
  @for (hero of heroes(); track $index) {
    <li>{{ `${hero.name} ${hero.lastName} - ${hero.email}` }}</li>
  }
</ul>

Navigation in der Liste ohne Komponentenmethoden

Die Aktualisierung des selectedHeroId-Signals erfolgt nun inline in Klick-Handlern. Statt prevHero()- und nextHero()-Methoden wird update() mit einer Lambda-Funktion verwendet:

<div class="hero-navigation">
  <button (click)="selectedHeroId.update(count => count === 1 ? heroes().length : count - 1)">Zurück</button>
  <div class="hero-name">
    {{ heroes()[selectedHeroId() - 1].name + ' ' + heroes()[selectedHeroId() - 1].lastName }}
  </div>
  <button (click)="selectedHeroId.update(count => count === heroes().length ? 1 : count + 1)">Weiter</button>
</div>
<div class="hero-info">
  {{ heroes()[selectedHeroId() - 1] | json }}
</div>

Dies reduziert Boilerplate-Code, aber die zyklische Navigationslogik (Rückkehr zum ersten Element) bleibt im Template.

Filtern und Suchen in Templates

Filtern von Helden durch Abgleich der ersten Buchstaben von Vor- und Nachnamen:

Google AdInline article slot
<div>
  {{ heroes().filter(hero => hero.name.charAt(0).toLowerCase() === hero.lastName.charAt(0).toLowerCase())
    .map(hero => `${hero.name} ${hero.lastName}`).join(', ') }}
</div>

Ergebnis: Peter Parker, Stephen Strange, Bruce Banner.

Suche nach E-Mail-Domain:

<div>
  {{ heroes().find(hero => hero.email.endsWith('stark.com'))?.name }}
</div>

Ausgabe: Tony.

Google AdInline article slot

Funktionen als Input an Kindkomponenten übergeben

Die Kindkomponente HeroesList akzeptiert eine Sortierfunktion über input:

@Component({
  selector: 'app-heroes-list',
  template: `
    <ul>
      @for (hero of sortedHeroes(); track $index;) {
        <li>{{ hero.name + ' ' + hero.lastName }}</li>
      }
    </ul>
  `,
  standalone: true
})
export class HeroesList {
  heroes: InputSignal<Hero[]> = input.required<Hero[]>();
  sortFn: InputSignal<(a: Hero, b: Hero) => number> = input.required<(a: Hero, b: Hero) => number>();

  sortedHeroes: Signal<Hero[]> = computed(() => [...this.heroes()].sort(this.sortFn()));
}

Verwendung im Eltern-Template:

<app-heroes-list [heroes]="heroes()" [sortFn]="(a, b) => a.name.localeCompare(b.name)"></app-heroes-list>

Sortiert nach Namen: Bruce Banner, Natasha Romanoff, Peter Parker, Stephen Strange, Tony Stark.

Objekte und Literale in Funktionen

Um Objekte zurückzugeben, wird die Funktion in Klammern eingeschlossen, um sie vom Funktionskörper zu unterscheiden:

<ul>
  @for (hero of heroes().map(item => ({ name: 'Super ' + item.nickname, email: item.email })); track $index) {
    <li>{{ `${hero.name} - ${hero.email}` }}</li>
  }
</ul>

Ergebnis: Super Spider man - [email protected], usw.

Grenzen reiner Funktionen

  • Mehrzeilige Funktionen werden nicht unterstützt:

```html

{{ heroes().map(item => { return { name: 'Super ' + item.nickname, email: item.email } }) }}

```

Der Compiler wirft einen Fehler.

  • Funktionen, die Funktionen zurückgeben, werden als Text kompiliert:

```html

{{ () => heroes().find(hero => hero.email.endsWith('stark.com'))?.name }}

```

  • Pipes innerhalb von Funktionen sind verboten, da dies kein reines JS ist:

```html

{{ heroes().find(hero => hero.email.endsWith('StaRk.com' | lowercase))?.name }}

```

Anwendung eines Pipes auf das Ergebnis ist erlaubt:

```html

{{ heroes().find(hero => hero.email.endsWith('stark.com'))?.name | uppercase }}

```

Ergebnis: TONY.

Wichtige Erkenntnisse

  • Reine Funktionen in Angular 21.2 Templates eignen sich für einfache Operationen mit Signals: Filtern, Suchen, Aktualisieren von Werten.
  • Obligatorische Verwendung von Klammern für Objektliterale und Verbot mehrzeiliger Ausdrücke.
  • Übergeben von Funktionen via Input-Signal erhält Reaktivität in Kindkomponenten.
  • Vermeiden Sie Pipes innerhalb von Funktionen; wenden Sie sie nur auf Ergebnisse an.
  • Performance: Reine Funktionen werden bei jeder Change Detection neu berechnet; bevorzugen Sie computed oder Pipes für komplexe Logik.

— Editorial Team

Advertisement 728x90

Weiterlesen