How to inherit a component in Angular and reuse its template
TL;DR. Point templateUrl
of your ChildComponent
to the Base component’s template file. Similarly, for the CSS file. You may override Base component’s CSS by adding multiple CSS files too. Here’s an example code.
@Component({
selector: 'eg-child',
templateUrl: './../base/base.component.html',
styleUrls: [
'./../base/base.component.scss',
'./child.component.scss',
],
})
export class ChildComponent extends BaseComponent {
// ...
}
A proper explanation
Class inheritance is pretty straightforward, even for an Angular Component class. You create a BaseComponent
class, and do ChildComponent extends BaseComponent
. However, the template is not inherited into ChildComponent
as it is part of the @Decorator
. So, you still have to set templateUrl: 'child.component.html'
and define its HTML again. In most cases, this may be fine because your ChildComponent
’s Template View may be different from that of the Base. But, what if it wasn’t; what if you wanted to simply reuse base.component.html
?
Usually, we end up making a compromise and do something like this.
@Component({
selector: 'eg-child',
template: `<eg-base></eg-base>`,
})
export class ChildComponent {
// ...
}
This is a compromise because this is a Composition of objects rather than Inheritance. Also, it may not be clear at the beginning, but it paves the path for further design compromises in future, OR you are not able to leverage the powers of object-oriented programming.
Problem 1: Accessing base component’s properties and methods
Sure, you can and access the base component and its properties and methods using @ViewChild(BaseComponent) baseComponent;
. But, to do so, you have to expose all of those properties and methods as public
.
Problem 2: Overriding base component’s properties and methods
You cannot solve this problem. Hence, you will end up creating @Input
and @Output
properties in your BaseComponent
to customize the Base’s behaviors.
A cleaner solution
First, of course, inherit your ChildComponent
from BaseComponent
. Next, point templateUrl
of your ChildComponent
to the Base’s template file. Similarly, for the CSS file too.
Note: URL path to base.component.html
or .scss
needs to be relative to your current ChildComponent
’s path. (Would be awesome if someone can tell me how to make it relative to the Angular app root, or node_modules
. I know this is possible.)
Pro-Tip: You can override the Base’s CSS by adding multiple CSS files to styleUrls
. This is useful when you need to have a different look and feel for your child component. Here is a detailed code example.
In this example, you can see the following behaviors and benefits.
- Child points to the template of the Base.
- Child points to the style of the Base and its own style.
- Base component contains the logic for API-data retrieval and Form-Building functionalities that are automatically available in the Child now.
- Protected properties and functions, like
entityType
,initFormGroup
, etc., are accessible only in inherited class. No more unnecessary public properties and functions. - In the Child component, the Base’s
entityType
is set in the constructor. - Base’s
initFormGroup
is overridden in the Child.
The above example could be tweaked further to make the base class generic, i.e. EntityFormComponent<T>
, thereby be able to define strongly-typed properties (like SomeEntityService<T>
) instead of any
.
Hope you found the information in this article useful. Open for comments and suggestions.