Ab Angular 16 kannst du Route-Parameter direkt über input() bzw. @Input() in deine Komponenten binden, ganz ohne ActivatedRoute. 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.

Angular: Framework für dynamische Single Page Applications
Angular ist eines der beliebtesten Frameworks für moderne Webanwendungen. Erfahre, was Angular ausmacht und wie du damit durchstartest.

🤔 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 Zahl
  • booleanAttribute, 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.

Warum du nur noch TypeScript nutzen solltest
TypeScript bietet dir Typsicherheit, bessere Tooling-Unterstützung und weniger Bugs. Erfahre, warum sich der Umstieg lohnt.

🎯 Vorteile: Warum du umsteigen solltest

  • Weniger Boilerplate, Kein ActivatedRoute, kein subscribe(), kein unsubscribe()
  • 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 mit computed() und effect() 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!