One of the new features introduced by Angular 16 is the ability to bind route parameters directly to component inputs. This addition improves the component’s isolation and makes them more reusable. This blog post aims to provide a step-by-step guide on how to enable and utilize this innovative feature.
Let’s say we have the following routes configuration:
export const routes: Routes = [
{
path: 'news',
loadComponent: () => import('./news/news.component'),
children: [
{
path: ':id',
loadComponent: () => import('./news/news-detail.component'),
},
]
},
];
For years we’ve been using the ActivatedRoute
service to retrieve route params
like the id
of the News Detail route.
And it’s been working pretty well so far.
However, this approach has a few drawbacks:
ActivatedRoute
service in every component that needs to retrieve route paramsparamMap
observable and thus, handle the unsubscriptionexport default class NewsDetailComponent implements OnInit {
private readonly route = inject(ActivatedRoute);
ngOnInit(): void {
this.route.paramMap.subscribe(params => {
const id = params.get('id');
})
}
}
With Angular 16, instead, we can remove all the boilerplate code and simply bind route params to component inputs.
In the following sections, we explore how to enable this feature both on a standard Angular application using modules and on a complete module-less app.
Just pass withComponentInputBinding()
to the provideRouter()
function.
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes, withComponentInputBinding())
]
};
The RouterModule.forRoot
static method accepts an object as the second argument to enable features.
Make sure to set bindToComponentInputs
to true
to bind route params to component inputs.
@NgModule({
imports: [
RouterModule.forRoot(routes, { bindToComponentInputs: true })
],
exports: [RouterModule]
})
export class AppRoutingModule { }
Now that we’ve enabled the feature, the id
property will be automatically bound to the id
route param.
export default class NewsDetailComponent {
@Input() id!: string;
}
With the paramMap
observable we were able to react to param changes but
we lost this ability when switching to the new approach.
To react on param changes, you can use the setter of the id
property.
This setter is called every time the id
route param changes.
In the example below, I reassigned the news$
observable every time the id
changes.
An async pipe in the template is used to subscribe to the observable and render the data.
export default class NewsDetailComponent {
news$?: Observable<News>;
_news = inject(NewsService);
@Input() set id(id: string) {
this.news$ = this._news.getById(id);
}
}
Router bindings are not limited to route params.
If you have data set at the route level, you can bind that as well and no extra configuration is required.
The new Angular 16 feature that binds route parameters and data directly to component inputs
promotes better component isolation, and simplifies testing by minimizing dependencies
on services like ActivatedRoute
.
This is again an effort from the Angular team to make the framework less verbose and more intuitive.