How to reduce duplicated code by using dependency injection in Angular

Using dependency injection to replace redundant logic code

Photo by Max Duzij on Unsplash
@Component({
...
})
export class SomeComponent implements OnInit {
constructor(
private route: ActivatedRoute
) {}
ngOnInit(): void {
this.route.params.pipe(
takeUntil(this.destroy$),
map(params => params.id),
filter(v => !!v),
// do something with this id
);
}
}

Declare injection token and factory function

export const ROUTE_PARAM_TOKEN = new InjectionToken<Observable<string>>(
'Stream of route param from activated route'
);
// if you want to get :id from route, declare this token
export const PARAM_KEY_ID = new InjectionToken<string>(
'static string for :id param key',
// this is the second argument of InjectionToken constructor
// to produce the value, like when you use useFactory
{
factory: () => {
return 'id';
}
}
);
// if you want to get :someId from the route, the token should look like this
export const PARAM_KEY_SOME_ID = new InjectionToken<string>(
'static string for :someId param key', {
factory: () => {
return 'someId';
}
}
);
export function routeParamFactory(
route: ActivatedRoute,
paramKey: string
): Observable<string> {
// should use paramMap because route.params will be deprecated soon
return route.paramMap.pipe(map((param) => param.get(paramKey)))
}

Declare the token in the provider list of your component

@Component({
providers: [
{
provide: ROUTE_PARAM_TOKEN,
useFactory: routeParamFactory,
deps: [ActivatedRoute, PARAM_KEY_ID]
// if you want to get someId, the deps will be
// deps: [ActivatedRoute, PARAM_KEY_SOME_ID]
}
]
})
export class SomeComponent {
constructor() {}
}

Inject the token in constructor and use it in your component

@Component({
providers: [
{
provide: ROUTE_PARAM_TOKEN,
useFactory: routeParamFactory,
deps: [ActivatedRoute, PARAM_KEY_ID]
}
]
})
export class SomeComponent implements Oninit {
constructor(
@Inject(ROUTE_PARAM_TOKEN)
private readonly id$: Observable<string> // should use readonly as much as possible
) {}
ngOnInit(): void {
this.id$.pipe(
// do whatever with this id
);
}
}

Angular Enthusiast