Carlos Cifuentes
AngularJS → Angular reference

$stateParams / $routeParams in modern Angular

With withComponentInputBinding, the router passes path params, query params and resolved data straight into component inputs. ActivatedRoute remains available when you need the raw values.

Before · AngularJS
app.controller('UserDetailCtrl', function ($stateParams, UserService) {
  var vm = this;
  vm.tab = $stateParams.tab || 'profile';
  UserService.get($stateParams.id).then(function (user) {
    vm.user = user;
  });
});
After · Angular
// app.config.ts
provideRouter(routes, withComponentInputBinding())

// route: { path: 'users/:id', component: UserDetailComponent }
export class UserDetailComponent {
  private users = inject(UserService);

  id = input.required<string>();     // :id
  tab = input('profile', {           // ?tab=
    transform: (v: string | undefined) => v ?? 'profile',
  });

  user = toSignal(
    toObservable(this.id).pipe(switchMap(id => this.users.get(id))),
  );
}

What changes

  • The input name must match the param name; the value arrives as a string, so convert numbers with a transform.
  • A missing query param arrives as undefined and replaces the input's default value; use a transform to restore the default.
  • The router reuses the component when only the params change, so react to the input instead of reading it once.

Migration tip. Old controllers read $stateParams once because ui-router rebuilt them on every transition. Check each one for that assumption; it is the usual reason a migrated detail screen shows stale data.

Related

Planning a migration or a micro-frontend platform?

In a 20-minute call you describe your situation and I tell you how I'd approach it. If it isn't worth doing yet, I'll say so.

Message me on LinkedIn