PART 1 — The Case For Component Inheritance In Angular

Angular is a very Enterprise friendly JS framework. I have spent the past 2 years building Enterprise software in healthcare and every day I solve a difficult problem with Angular, I really get this happy feeling thankful that we stuck with Angular.

The Issue Explained

I found myself building a healthcare application in the mental health industry since 2016. Basically, we have a Psychology application that uses some content we created to help users improve their mental health. Now each of our content is sort of like a course or examination that has some questions for the users to answer. These questions or BLOCKS as we call them are spread out across multiple pages.

Pages & Questions

Our application has different types of Questions, and there are some things that all Question blocks have in common. Let us start with what each Question block has in common. A typical Question block has a Header & Content.

A Typical Question Block

The header basically exists to act as a title, while the content area houses different types of things. For example, in some Questions, the content is just text for the user to read, but it could also be a Radio-Group, a Video/Picture or even just a TextArea requiring user input.

Typically you would expect that we create a component for each type of Question block that our application supports and this would actually be the right way to proceed. So we did go ahead and create a component for each question type. However, this technique would not solve a very important problem and requirement that our company has. We have a number of clients and each client wants a different look and feel, so we cannot use one component as we cannot change the markup of one component without a really messy template that is coupled with soo much if/else logic. Also, we have cases where a specific client might ask us for a very specific feature that only they themselves want inside their own application alone.

Component Inheritance To The Rescue

This is where arguably, Angular’s least used and discussed feature comes to the fray. What is Component inheritance in Angular and what does it look like? Component inheritance in Angular relies on the built-in concept of inheritance that Object Oriented Programming (OOP) makes available for use VIA the extends keyword.

Component B Inheriting From Component A
Code Demonstrating Component Inheritance

From the illustrations above, ComponentB will basically now have a property called name even though it doesn’t explicitly have this “name” property. This is how inheritance works but since we are using Angular, there are also some few other benefits we get from component inheritance.

Let us understand some key limitations & features on Angular’s component inheritance system.

  • The component only inherits the class logic
  • All meta-data in the @Component decorator is not inherited
  • Component @Input properties and @Output properties are inherited
  • Component lifecycle is not inherited

These features are very important to have in mind so let us examine each one independently.

The Component only inherits the class logic

When you inherit a Component, all logic inside is equally inherited. It is worth noting that only public members are inherited as private members are only accessible in the class that implements them.

Component Inheritance Shown

All meta-data in the @Component decorator is not inherited

The fact that no meta-data is inherited might seem counter-intuitive at first but, if you think about this it actually makes perfect sense. If you inherit from a Component say (componentA), you would not want the selector of ComponentA, which you are inheriting from to replace the selector of ComponentB which is the class that is inheriting. The same can be said for the template/templateUrl as well as the style/styleUrls.

Component @Input and @Output properties are inherited

Component Input Inheritance

This is another feature that I really love about component Inheritance in Angular. In a simple sentence, whenever you have a custom @Input and @Ouput property, these properties get inherited.

Component B In Use

You can see that ComponentB is using the name property it inherited from ComponentA

Component lifecycle is not inherited

This part is the one that is not soo obvious especially to people who have not extensively worked with OOP principles. For example, say you have ComponentA which implements one of Angular’s many lifecycle hooks like OnInit. If you create ComponentB and inherit ComponentA, the OnInit lifecycle from ComponentA won't fire until you explicitly call it even if you do have this OnInit lifecycle for ComponentB.

Let us take a look at this phenomenon in practice.

You can see that the Base component which in this case is ComponentA implements Angular’s OnInit lifecycle interface. If you use the ComponentB class, the console message would never be called.

Now let us have a look at how we can fix this.

Calling Super/Base Component Methods

In order to have the ngOnInit() method from ComponentA fire, we need to use the super keyword and then call the method we need which in this case is ngOnInit. The super keyword refers to the instance of the component that is being inherited from which in this case will be ComponentA.

Lifecycle Being Inherited

The lifecycle of the superclass is only a function and this function can be called at the developer's discretion and doesn't have to be solely called inside of the ngOnInit of ComponentB.

Roundup

By now, you have a firm understanding of how component inheritance in Angular works. This article is the first part of a series so be sure to read part 2 to see how we solve the white labelling issue.