Binding Router Information to Routed Component Inputs in Angular

Netanel Basal
Netanel Basal
Published in
2 min readApr 4, 2023

--

Angular v16 has introduced a powerful new feature that enables the automatic binding of router information, such as query parameters, path parameters, static data, and resolver data to a routed component’s inputs.

This functionality can be activated using the withComponentInputBinding function. Here’s an example of how to use it:

import { bootstrapApplication } from '@angular/platform-browser';
import { provideRouter, withComponentInputBinding } from '@angular/router';

bootstrapApplication(AppComponent, {
providers: [
provideRouter(
[
{
path: '',
pathMatch: 'full',
loadComponent: () => import('./app/home/home.component'),
},
{
path: 'todo',
loadComponent: () => import('./app/todo/todo.component'),
},
],
// 👇👇👇
withComponentInputBinding()
),
],
});

With this feature, the router outlet component listens to the activated route query parameters, path parameters, and data observables and automatically calls the setInput method with the initial value and when it changes.

For example, suppose we have an id query parameter in our URL and want to fetch the current entity. In this case, our URL will be /todo?id=1, and our component will look like this:

@Component({
...
standalone: true,
})
export default class TodoComponent {
private todosService = inject(TodosService);

todo$: Observable<Todo>;

// The input name should be the same as the query param key
@Input() set id(value: string) {
this.todo$ = this.todosService.get(value);
}
}

Similarly, if we have a search term in our URL (e.g /foo?searchTerm=bar), we can update our form control with its value:

@Component({
...
standalone: true,
imports: [ReactiveFormsModule],
})
export default class FooComponent {
searchControl: FormControl<string>;

@Input() searchTerm: string;

ngOnInit() {
this.searchControl = new FormControl(this.searchTerm || '');
}
}

In cases of conflicts, the priority is set based on the following: data > path parameters > query parameters.

Here’s an example that demonstrates all the valid use cases:

bootstrapApplication(AppComponent, {
providers: [
provideRouter(
[
{
path: 'todos/:todoId',
data: {
isSomething: true,
},
resolve: { resolveFoo: () => 'My resolved data' },
loadComponent: () => import('./app/todo/todo.component'),
},
],
withComponentInputBinding()
),
],
});

Suppose our URL is /todos/1?searchTerm=angular, and our component looks like this:

@Component({
...
standalone: true,
})
export default class TodoComponent {
@Input() resolveFoo: string; // My resolved data
@Input() isSomething: boolean; // true
@Input() todoId: string; // 1
@Input() searchTerm: string; // angular
}

Overall, this new feature streamlines the process of passing router information to routed components, and reducing the need for boilerplate code.

Follow me on Medium or Twitter to read more about Angular and JS!

--

--

A FrontEnd Tech Lead, blogger, and open source maintainer. The founder of ngneat, husband and father.