← All articles

Handling Route Parameters with Angular withComponentInputBinding

Angular v17 withComponentInputBinding and signal inputs simplify route params compared with ActivatedRoute subscriptions, with clearer types and effects.

Published
Handling Route Parameters with Angular withComponentInputBinding cover image

Angular v17's withComponentInputBinding combined with signal inputs dramatically improves how you handle route parameters. This article shows migration patterns from the old approach to the new one. (Yes, this is late—but I had a project that kept putting migration off, and I wrote this as reference material for generative AI.)

Comparing the old and new approaches

1. Getting params from ActivatedRoute

To get params from ActivatedRoute, you either subscribe to paramMap or read snapshot.paramMap.

Old approach

@Component({
  // ...
})
export class UserDetailComponent implement OnInit {
  userId: string;
  route = inject(ActivatedRoute);

  ngOnInit() {
    // Pattern paramMap
    this.route.paramMap.subscribe(params => {
      this.userId = params['id'];
    });

    // Pattern snapshot
    this.userId = this.route.snapshot.paramMap.get('id');
  }
}

New approach

With withComponentInputBinding, you can write:

@Component({
  // ...
})
export class UserDetailComponent {
  userId = input<string>();
}

This feature binds the following directly to component inputs:

  • Query parameters
  • Path and matrix parameters
  • Static route data
  • Resolver data

2. When you subscribed to paramsMap for other work

You may also have run other logic whenever paramsMap changed.

Old approach

@Component({
  // ...
})
export class UserDetailComponent implement OnInit {
  route = inject(ActivatedRoute);
  userService = inject(UserService);
  userId: string;
  userData: IUser;

  ngOnInit() {
    this.route.paramMap.subscribe(params => {
      this.userId = params.get('id')!;
      this.loadUserData();
    });
  }

  private loadUserData() {
    this.userService.getUser(this.userId).subscribe(data => {
      this.userData = data;
    });
  }
}

New approach

Use an effect to react to signal inputs. Note that when no matching route key exists, the input is set to undefined. That prevents stale values when route data is removed (for example, when a query parameter is dropped).

@Component({
  // ...
})
export class UserDetailComponent {
  route = inject(ActivatedRoute);
  userService = inject(UserService);
  userId = input<string>();
  userData: IUser;

  constructor() {
    effect(() => {
      const id = this.userId();
      if (id) {
        this.userService.getUser(id).subscribe(data => {
          this.userData = data;
        });
      }
    })
  }
}

Benefits of the new approach

The old approach required injecting ActivatedRoute and subscribing. The new approach needs only signal inputs. Code becomes more declarative and type-safe.

Signal inputs also simplify component inputs and make tests easier to write. When route parameter changes should trigger other work, effect keeps the code declarative.

Summary

withComponentInputBinding with signal inputs greatly improves route parameter handling. Code is shorter, types are safer, and performance improves—a win on all three fronts.

New projects should use it by default, and existing projects are worth migrating incrementally. Components with complex route parameter logic should show the benefit clearly.