Ab Angular 16 kannst du Route-Parameter direkt überinput()bzw.@Input()in deine Komponenten binden, ganz ohneActivatedRoute. Das Ergebnis: weniger Boilerplate, kein manuelles Subscriben und sauberer, reaktiver Code.
Wenn du schon länger mit Angular arbeitest, kennst du das Spiel: Du willst einen Parameter aus der URL lesen und landest sofort bei ActivatedRoute, subscribe() und einer ganzen Menge Boilerplate. Das war jahrelang der Standard, aber seit Angular 16 gibt es einen deutlich eleganteren Weg. In diesem Artikel zeige ich dir, wie du mit input() Route-Parameter direkt in deine Komponente bindest.
🤔 Der klassische Weg: ActivatedRoute
Bisher musstest du für jeden Route-Parameter den ActivatedRoute-Service injizieren und die Parameter manuell subscriben:
import { Component, OnInit, OnDestroy } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';
@Component({
selector: 'app-product-detail',
template: `<h1>Produkt {{ productId }}</h1>`
})
export class ProductDetailComponent implements OnInit, OnDestroy {
productId: string = '';
private sub!: Subscription;
constructor(private route: ActivatedRoute) {}
ngOnInit() {
this.sub = this.route.params.subscribe(params => {
this.productId = params['id'];
});
}
ngOnDestroy() {
this.sub.unsubscribe();
}
}Das funktioniert, ist aber verbose: Du brauchst den Service, ein Subscription-Management und musst dich um OnDestroy kümmern. Bei mehreren Parametern wird es schnell unübersichtlich.
🚀 Der neue Weg: input() für Route-Parameter
Seit Angular 16 kannst du Route-Parameter direkt als Input binden. Das funktioniert sowohl mit dem klassischen @Input()-Decorator als auch mit dem neuen Signal-basierten input().
Variante 1: @Input() Decorator
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-product-detail',
standalone: true,
template: `<h1>Produkt {{ id }}</h1>`
})
export class ProductDetailComponent {
@Input() id!: string;
}Variante 2: input() Signal (empfohlen)
import { Component, input } from '@angular/core';
@Component({
selector: 'app-product-detail',
standalone: true,
template: `<h1>Produkt {{ id() }}</h1>`
})
export class ProductDetailComponent {
id = input.required<string>();
}Das war's! Kein ActivatedRoute, kein subscribe(), kein OnDestroy. Der Parameter-Name muss dabei mit dem Namen in der Route-Konfiguration übereinstimmen.
✏️ Route-Konfiguration
Die Route wird ganz normal definiert, der Parametername (:id) muss mit dem Input-Namen in der Komponente übereinstimmen:
export const routes: Routes = [
{
path: 'products/:id',
component: ProductDetailComponent
}
];Wenn du die URL /products/42 aufrufst, wird id automatisch auf "42" gesetzt.
⚙️ Setup: Component Input Binding aktivieren
Damit Angular weiß, dass es Route-Parameter an Inputs binden soll, musst du das Feature einmalig aktivieren. Je nach Projektstruktur gibt es zwei Wege:
Standalone Apps (empfohlen)
// app.config.ts
import { provideRouter, withComponentInputBinding } from '@angular/router';
import { routes } from './app.routes';
export const appConfig = {
providers: [
provideRouter(routes, withComponentInputBinding())
]
};NgModule-basierte Apps
// app.module.ts
@NgModule({
imports: [
RouterModule.forRoot(routes, {
bindToComponentInputs: true
})
]
})
export class AppModule {}Ohne diese Konfiguration bleibt der Input undefined, das ist der häufigste Fehler, wenn das Feature nicht funktioniert!
🔧 Transform-Funktionen: Typen automatisch konvertieren
Route-Parameter kommen immer als String aus der URL. Wenn du eine Zahl brauchst, kannst du Transform-Funktionen nutzen, die Angular mitliefert:
import { Component, input } from '@angular/core';
import { numberAttribute } from '@angular/core';
@Component({
selector: 'app-product-detail',
standalone: true,
template: `<h1>Produkt #{{ id() }}</h1>`
})
export class ProductDetailComponent {
// Automatische Konvertierung von string zu number
id = input.required({ transform: numberAttribute });
}Angular bietet unter anderem diese Transform-Funktionen:
numberAttribute, konvertiert den String in eine ZahlbooleanAttribute, konvertiert in einen Boolean- Eigene Funktionen:
transform: (value: string) => value.toUpperCase()
Das ist besonders praktisch, weil du damit TypeScript-Typsicherheit bekommst, ohne manuell casten zu müssen.
🎯 Vorteile: Warum du umsteigen solltest
- Weniger Boilerplate, Kein
ActivatedRoute, keinsubscribe(), keinunsubscribe() - Deep Linking, Parameter sind direkt in der URL, SSR und SEO funktionieren out-of-the-box
- Testbarkeit, Inputs lassen sich in Unit-Tests viel einfacher mocken als
ActivatedRoute - Signal-Integration, Mit
input()bekommst du reaktive Signals, die sich perfekt mitcomputed()undeffect()kombinieren lassen - Konsistenz, Query-Parameter, Path-Parameter und Route-Data nutzen alle denselben Mechanismus
Übrigens: Auch Query-Parameter und Route-Data lassen sich auf dieselbe Art binden. Ein Input namens search greift z.B. automatisch auf den Query-Parameter ?search=... zu.
💡 Fazit
Mit input() für Route-Parameter wird Angular-Code deutlich schlanker. Du sparst dir den ganzen ActivatedRoute-Boilerplate und bekommst reaktive, typsichere Parameter-Bindings quasi geschenkt. Wenn du noch auf dem klassischen Weg unterwegs bist: Jetzt ist der perfekte Zeitpunkt zum Umsteigen!