Services sind ein Kernkonzept in Angular und stellen eine Möglichkeit dar, wiederverwendbare Logik zu kapseln, die in verschiedenen Teilen Ihrer Anwendung genutzt werden kann. Angular bietet verschiedene Features, die die Verwendung und Performance von Services optimieren.
Ein Service ist eine Klasse mit einem spezifischen Zweck. Sie bieten Funktionalitäten wie Datenzugriff, Nutzerkommunikation, Logging, Business-Logik und mehr. Der Hauptzweck von Services ist die Trennung von Zuständigkeiten, indem Logik aus den Komponenten ausgelagert wird, wodurch:
In Angular können Services mit dem Angular CLI erstellt werden:
ng generate service my-serviceDies erzeugt folgende Dateien: - my-service.service.ts -
Die Service-Implementierung - my-service.service.spec.ts -
Testdatei für den Service
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class DataService {
private data: string[] = [];
constructor() { }
getData(): string[] {
return this.data;
}
addData(item: string): void {
this.data.push(item);
}
}Der @Injectable-Dekorator markiert eine Klasse als
Service, die in Angulars Dependency Injection (DI) System registriert
werden kann. Es gibt verschiedene Möglichkeiten für die
Konfiguration:
@Injectable({
providedIn: 'root', // Anwendungsweit verfügbar
// providedIn: 'any', // Verfügbar für alle Lazy-Loading-Module
// providedIn: SomeModule, // Verfügbar nur in einem bestimmten Modul
})Um einen Service in einer Komponente zu verwenden:
import { Component } from '@angular/core';
import { DataService } from './data.service';
@Component({
selector: 'app-data-display',
template: `
<div>
<h2>Daten:</h2>
<ul>
<li *ngFor="let item of items">{{ item }}</li>
</ul>
<button (click)="addItem()">Neues Element hinzufügen</button>
</div>
`
})
export class DataDisplayComponent {
items: string[] = [];
constructor(private dataService: DataService) {
this.items = this.dataService.getData();
}
addItem(): void {
const newItem = `Element ${this.items.length + 1}`;
this.dataService.addData(newItem);
this.items = this.dataService.getData();
}
}Angular bietet mehrere Ebenen, auf denen Services bereitgestellt werden können:
@Component({
selector: 'app-special',
providers: [SpecialService], // Komponenten-spezifische Instance
template: '...'
})
export class SpecialComponent { }Ein häufiger Anwendungsfall für Services ist die Kommunikation mit APIs:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class ApiService {
private apiUrl = 'https://api.example.com/data';
constructor(private http: HttpClient) { }
fetchData(): Observable<any[]> {
return this.http.get<any[]>(this.apiUrl);
}
saveData(data: any): Observable<any> {
return this.http.post<any>(this.apiUrl, data);
}
}Ein Service kann andere Services injizieren, um komplexere Funktionalitäten zu implementieren:
import { Injectable } from '@angular/core';
import { ApiService } from './api.service';
import { LogService } from './log.service';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class DataManagerService {
constructor(
private apiService: ApiService,
private logService: LogService
) { }
processData(): Observable<any[]> {
this.logService.log('Daten werden abgerufen...');
return this.apiService.fetchData().pipe(
tap(data => {
this.logService.log(`${data.length} Elemente abgerufen`);
})
);
}
}In neueren Angular-Versionen können Services als Teil des Standalone-API-Konzepts verwendet werden:
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class StandaloneService {
getValue(): string {
return 'Ich bin ein Service!';
}
}Ein leistungsstarkes Muster in Angular ist die Kombination von Services mit RxJS:
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class StateService {
private stateSubject = new BehaviorSubject<any>({
isLoading: false,
data: null,
error: null
});
// Öffentliche Observable für Komponenten
public state$ = this.stateSubject.asObservable();
constructor() { }
updateState(newState: Partial<any>): void {
this.stateSubject.next({
...this.stateSubject.value,
...newState
});
}
setLoading(isLoading: boolean): void {
this.updateState({ isLoading });
}
setData(data: any): void {
this.updateState({ data, isLoading: false, error: null });
}
setError(error: any): void {
this.updateState({ error, isLoading: false });
}
}Verwendung in einer Komponente:
@Component({
selector: 'app-data-view',
template: `
<div *ngIf="(state$ | async)?.isLoading">Laden...</div>
<div *ngIf="(state$ | async)?.error">Fehler: {{ (state$ | async)?.error }}</div>
<div *ngIf="(state$ | async)?.data">
{{ (state$ | async)?.data | json }}
</div>
`
})
export class DataViewComponent {
state$: Observable<any>;
constructor(private stateService: StateService) {
this.state$ = this.stateService.state$;
}
loadData(): void {
this.stateService.setLoading(true);
// Datenabruf...
}
}Angular bietet umfangreiche Testmöglichkeiten für Services:
// data.service.spec.ts
import { TestBed } from '@angular/core/testing';
import { DataService } from './data.service';
describe('DataService', () => {
let service: DataService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(DataService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
it('should add data correctly', () => {
service.addData('Test Item');
expect(service.getData()).toContain('Test Item');
expect(service.getData().length).toBe(1);
});
});Services in Angular sind ein mächtiges Werkzeug zur Organisation von Anwendungslogik. Sie bieten Flexibilität und Performance bei der Entwicklung von robusten Anwendungen.