Services kommen in Angular immer dann zum Einsatz, wenn Daten oder Methoden zwischen Komponenten geteilt werden sollen, die in keiner direkten Beziehung zueinander stehen. Es handelt sich also um Situationen, in denen keine klassische Übergabe von Daten zwischen Eltern- und Kindkomponenten stattfindet. Auch wenn ein solcher Einsatz prinzipiell ebenfalls möglich wäre. Häufig übernimmt ein Service die Rolle einer Repository-Klasse, die Daten verwaltet, auf die mehrere Komponenten gleichzeitig zugreifen. Die Implementierung erfolgt dabei in der Regel in Form eines Singletons, sodass nur eine einzige Instanz der Klasse existiert. Über Dependency Injection wird diese Instanz anschließend in den benötigten Komponenten verfügbar gemacht. Das folgende Listing zeigt die Klasse DataService mit dem Dateinamen data.service.ts. Die Aufgabe dieser Klasse besteht derzeit lediglich darin, eine Liste von Ländern mit ihren Hauptstädten bereitzustellen. Dennoch kann diese Klasse bereits als vollwertiger Service genutzt werden. Im Code ist dies gut erkennbar am Import von Injectable und dem zugehörigen @Injectable-Dekorator. Die Angabe providedIn: 'root' legt fest, dass der Service als Singleton auf Root-Ebene der Anwendung zur Verfügung steht. Angular erzeugt dabei automatisch eine einzige, gemeinsam genutzte Instanz des Services, die in allen Bereichen der Anwendung verfügbar ist. Sollte der Service bei der Entwicklung dann doch an keiner Stelle verwendet werden, entfernt Angular ihn beim Kompilieren automatisch.
import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class DataService { public countries: { name: string; capital: string }[] = []; constructor() { this.countries = [ { name: 'Deutschland', capital: 'Berlin' }, { name: 'Frankreich', capital: 'Paris' }, { name: 'Italien', capital: 'Rom' }, { name: 'Spanien', capital: 'Madrid' }, { name: 'Japan', capital: 'Tokio' }, { name: 'Kanada', capital: 'Ottawa' }, { name: 'Australien', capital: 'Canberra' } ]; } }
Es bleibt die Frage, wie dieser Service nun in anderen Komponenten verwendet werden kann. Dabei kommt die zuvor erwähnte Dependency Injection ins Spiel, die in Angular beinahe wie von selbst funktioniert. Es genügt, den Service im Konstruktor einer Komponente anzugeben, und das Framework übergibt die Instanz automatisch an die Klasse. Im folgenden Listing wurde der Parameter als public deklariert und kann anschließend ohne weiteren Aufwand direkt im HTML-Template genutzt werden. Genauso wie jede andere Eigenschaft, die in der Komponente definiert wurde.
import { Component } from '@angular/core'; import { DataService} from "./data.service"; @Component({ selector: 'app-dataservice-sample', standalone: true, imports: [], templateUrl: './dataservice-sample.component.html', styleUrl: './dataservice-sample.component.scss' }) export class DataserviceSampleComponent { constructor(public dataService: DataService) { } }
Im HTML-Template lässt sich das Array mit den Ländern anschließend sehr einfach ausgeben. Eine for-Schleife reicht dazu vollkommen aus. Zu beachten ist dabei das Schlüsselwort track, das Angular hilft, die einzelnen Elemente einer Liste eindeutig zu identifizieren. Dadurch kann das Framework effizient bestimmen, welche DOM-Elemente aktualisiert, hinzugefügt oder entfernt werden müssen. Im Beispiel erfolgt die Identifizierung über den Namen eines Landes. Diese Lösung ist nicht ideal, aber in diesem speziellen Fall ausreichend, weil die Ländernamen innerhalb der Datenliste einmalig sind. Eleganter wäre es, jedem Land eine eindeutige ID zu geben, um die Elemente über track country.id identifizieren zu können. Dadurch würden spätere Erweiterungen oder Änderungen der Datenstruktur robuster und einfacher handhabbar.
Countries and Capitals
Um das Erscheinungsbild aufzuwerten, kann die Liste der Länder alternativ auch in einer Tabelle ausgegeben werden.
Countries and Capitals
Land |
Hauptstadt |
|---|---|
| {{ country.name }} | {{ country.capital }} |