Angular: Inheritance Without Effort

A great way of using inheritance in our app without maintenance

Kevin MATHY
Jul 29, 2019 · 4 min read
Photo by Jakub Gorajek on Unsplash

Written in TypeScript, Angular makes it possible to use the concept of inheritance in our components.

However, we face a problem when we want services in child components.


Getting Started

Let’s start by creating our BaseComponent:

See that the decorator Component is not necessary — we don’t have to declare this class in the module, as it is not a component. We can also declare it as an abstract class as we would do in regular OOP language.

Then, we create our two components extended by the BaseComponent:

When we navigate from one component to another, the logs are correctly printed in the console.

Our child components are now ready!

However, in the AComponent, I would like to access its ElementRef (or another service):

And here is our problem. When I want to inject ElementRef in that component, I have to call the method super() and pass our two other classes. Imagine, if you have other services in the BaseComponent, it will be hard to manage the children.

If I add or remove a service in BaseComponent, I have to reflect these changes in every child component extended by it.

Fortunately, there is a solution which is easy to implement. We will inject our services into the BaseComponent manually.

For this example, I will create another BaseComponent containing our Injector — let’s call it BaseWithInjectorComponent:

The main change is in the constructor. Instead of using it to let Angular inject our services, we do this operation manually.

I put Injector and then I bind every injectable to its corresponding property. And that’s it!

We can now refactor our child component by removing the unnecessary arguments in the constructor:

Everything works like a charm. But, we’ll still always have to inject the Injector… We can do better!

Our goal is to remove the injector from our base constructor but we don’t have access to the instance of Injector without instantiating it in the constructor.

In fact, we can create our own Injector when we bootstrap our app and serve it as a singleton. Let’s do this!

Let’s create the app-injector.service.ts in /src :

This will keep our custom injector available as a singleton. We set it once in the AppModule constructor:

We can now use it safely in our base component:

To test if all is working as expected, I will modify the CComponent and the DComponent:

And, we also have the DComponent with the same structure but without ActivatedRoute.

When I navigate from one component to another, the results below demonstrate the working example:

Everything’s working as expected!

And our children are now empty of these dependencies in the super() method!


Exceptions of Inheritance

ActivatedRoute

If you want to inject ActivatedRoute in your BaseComponent, it won’t work properly. This class needs to be injected into the component to be correctly instantiated.

However, if you want the route state, I recommend you take a look at the Redux pattern instead of using inheritance, it will make your life easier.

Here is an example for NGXS.

You can also choose another state management library such as NgRx or Akita, or create your own with RxJS.

ElementRef

ElementRef, declared in the component’s constructor, provides the host element. In the abstracted component, it won’t be available — you will get No provider for ElementRef even if you use your injector.

So, if you need it, you will have to pass it in your child constructor.


Warning: use with caution

The pattern used in this example is known as the ServiceLocator pattern.

It is known as an anti-pattern, so keep in mind to ONLY use it in base components. For example, FormBaseComponent, BaseComponent,… UI components which don’t care about these dependencies.

More info about the ServiceLocator Pattern: https://en.wikipedia.org/wiki/Service_locator_pattern


Conclusion

We have now an excellent way of using inheritance in our app with no maintenance. Inheritance is great to avoid repeatable actions in our components and we can build a smart component if we use it wisely.

However, it might not be the best solution for everything — think about it twice before designing your hierarchy.

Have a nice day!

Better Programming

Advice for programmers.

Kevin MATHY

Written by

Web developer & Angular Specialist

Better Programming

Advice for programmers.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade