Passing route params into angular component’s Input() properties

Andrew Cherepovskiy
4 min readApr 25, 2020

--

One of the most duplicating angular code that I have written in my angular dev career was about passing route params to components:

Because it is a common way to pass params from route to the component, this code with subscribe on init and unsubscribe on destroy repeating dozens of times.

And the idea of passing these parameters as components’ Input() props seems very obvious.

I started to google such approach and found out, that is a pretty common question and there is even an open feature request (from 2017) to the angular team to make it possible:

So, I decided to implement such logic on my own. And want to share with you my approach and the resulting npm library.

If you don't want to dive into my implementation, but want to try it on your project, you can simply check the npm package:

npm i --save ngx-route-params-input

The implementation:

The main idea was to create a “wrapper” component, which will be able to programmatically render needed components and pass all the router params as its props:

  1. Create WrapperComponent:
wrapper.component.ts

Property “container” refers to a place where our own components will be rendered.

2. The most suitable place to pass the component’s config is the route “data” field, which can also be subscribed as rxjs Observable inside our wrapper:

On this step, we moved MyComponent to route data and put our new WrapperComponent in its previous place. As we can see, MyComponent is rendering, but no data passed:

MyComponent has been rendered programmatically by WrapperComponent

3. Add “helper” function to receive all param values from ActivatedRouteSnapshot from root:

This is a small helper, which allows getting all passed route params from all snapshots from the root to activated.

4. Extend route data with router param configuration and adding logic to WrapperComponent for accept data from the route.

In this step, I added new property “routeParams”, which will be the mapping config of the route.

This is better — MyComponent is rendering and data passed into it:

Data from the route is being passed to MyComponent by WrapperComponent

However, there are still some problems with this implementation:

  • ngOnChanges hook is not being triggered when routing params change
  • the params passed into the component even there is no Input decorator for those properties, or even worse: there can be no such property at all

5. Adding ngOnChanges support:

The idea was to trigger ngOnChanges manually when route params changed.
This method accepts an argument of type SimpleChanges

wrapper.component.ts (only changes to prev implementation)

On these steps, we are starting to check what changed within input props. Pay attention that some prev defined properties can become empty on route changes.

Then with these changes, we are forming “SimpleChanges object and pass it to components’ “ngOnChangesmethod.

In addition, “SimpleChange” entities need information whether it was the first change or not. That’s why I added property object “isNotFirstChangeCollection” to store whether there was its first change.

6. Checking component properties for “Input” property decorators and allowing to pass props not only by its name but by Input decorators’ argument:

@Input('inputName')
public propName: string;

6.1. Implementation of checking component’s constructor for its Input props and make map object, where keys are the passed Input argument (“inputName” in the code above), and values are the property names (“propName” in the code above). In case there is no argument passed into Input decorator, key and value will be the same and refers to components’ property name.

This one is a tricky one, and its implementation depends on if your app was AOT or JIT compiled. Since it relies on inner angular properties, they can be changed in future and such changes need to be additionally supported by the lib, however, I was not able to find problems with latest angular versions, and, for example, “__prop__metadata__” property has not been changed for several major versions of angular.

6.2. Adjust WrapperComponent to use “getInputMap” method:

Final result:

Or use npm lib:

You can use my npm lib instead of writing the logic on your own. It has some differences and features, which were not covered by this article:

  • support of query (GET) parameters as well
  • changed route data interface in order not to conflict with your route data configurations
  • some error logging

--

--