I would like to create extensions for some components already deployed in Angular 2, without having to rewrite them almost completely, as the base component could undergo ch
As far as I know component inheritance has not been implemented yet in Angular 2 and I'm not sure if they have plans to, however since Angular 2 is using typescript (if you've decided to go that route) you can use class inheritance by doing class MyClass extends OtherClass { ... }
. For component inheritance I'd suggest getting involved with the Angular 2 project by going to https://github.com/angular/angular/issues and submitting a feature request!
This may not be the answer you're hoping for, but it is a solution.
npm install vue
Work Cited
Vue
if you read through the CDK libraries and the material libraries, they're using inheritance but not so much for components themselves, content projection is king IMO. see this link https://blog.angular-university.io/angular-ng-content/ where it says "the key problem with this design"
I know this doesn't answer your question but I really think inheriting / extending components should be avoided. Here's my reasoning:
If the abstract class extended by two or more components contains shared logic: use a service or even create a new typescript class that can be shared between the two components.
If the abstract class... contains shared variables or onClicketc functions, Then there will be duplication between the html of the two extending components views. This is bad practice & that shared html needs to be broken into Component(s). These Component(s) (parts) can be shared between the two components.
Am I missing other reasons for having an abstract class for components?
An example I saw recently was components extending AutoUnsubscribe:
import { Subscription } from 'rxjs';
import { OnDestroy } from '@angular/core';
export abstract class AutoUnsubscribeComponent implements OnDestroy {
protected infiniteSubscriptions: Array<Subscription>;
constructor() {
this.infiniteSubscriptions = [];
}
ngOnDestroy() {
this.infiniteSubscriptions.forEach((subscription) => {
subscription.unsubscribe();
});
}
}
this was bas because throughout a large codebase, infiniteSubscriptions.push()
was only used 10 times. Also importing & extending AutoUnsubscribe
actually takes more code than just adding mySubscription.unsubscribe()
in the ngOnDestroy()
method of the component itself, which required additional logic anyway.
just use inheritance,Extend parent class in child class and declare constructor with parent class parameter and this parameter use in super().
1.parent class
@Component({
selector: 'teams-players-box',
templateUrl: '/maxweb/app/app/teams-players-box.component.html'
})
export class TeamsPlayersBoxComponent {
public _userProfile:UserProfile;
public _user_img:any;
public _box_class:string="about-team teams-blockbox";
public fullname:string;
public _index:any;
public _isView:string;
indexnumber:number;
constructor(
public _userProfilesSvc: UserProfiles,
public _router:Router,
){}
2.child class
@Component({
selector: '[teams-players-eligibility]',
templateUrl: '/maxweb/app/app/teams-players-eligibility.component.html'
})
export class TeamsPlayersEligibilityComponent extends TeamsPlayersBoxComponent{
constructor (public _userProfilesSvc: UserProfiles,
public _router:Router) {
super(_userProfilesSvc,_router);
}
}
Alternative Solution:
This answer of Thierry Templier is an alternative way to get around the problem.
After some questions with Thierry Templier, I came to the following working example that meets my expectations as an alternative to inheritance limitation mentioned in this question:
1 - Create custom decorator:
export function CustomComponent(annotation: any) {
return function (target: Function) {
var parentTarget = Object.getPrototypeOf(target.prototype).constructor;
var parentAnnotations = Reflect.getMetadata('annotations', parentTarget);
var parentAnnotation = parentAnnotations[0];
Object.keys(parentAnnotation).forEach(key => {
if (isPresent(parentAnnotation[key])) {
// verify is annotation typeof function
if(typeof annotation[key] === 'function'){
annotation[key] = annotation[key].call(this, parentAnnotation[key]);
}else if(
// force override in annotation base
!isPresent(annotation[key])
){
annotation[key] = parentAnnotation[key];
}
}
});
var metadata = new Component(annotation);
Reflect.defineMetadata('annotations', [ metadata ], target);
}
}
2 - Base Component with @Component decorator:
@Component({
// create seletor base for test override property
selector: 'master',
template: `
<div>Test</div>
`
})
export class AbstractComponent {
}
3 - Sub component with @CustomComponent decorator:
@CustomComponent({
// override property annotation
//selector: 'sub',
selector: (parentSelector) => { return parentSelector + 'sub'}
})
export class SubComponent extends AbstractComponent {
constructor() {
}
}
Plunkr with complete example.
Components can be extended as same as a typescript class inheritance, just that you have to override the selector with a new name. All Input() and Output() Properties from the Parent Component works as normal
Update
@Component is a decorator,
Decorators are applied during the declaration of class not on objects.
Basically, decorators add some metadata to the class object and that cannot be accessed via inheritance.
If you want to achieve the Decorator Inheritance I would Suggest writing a custom decorator. Something like below example.
export function CustomComponent(annotation: any) {
return function (target: Function) {
var parentTarget = Object.getPrototypeOf(target.prototype).constructor;
var parentAnnotations = Reflect.getMetadata('annotations', parentTarget);
var parentParamTypes = Reflect.getMetadata('design:paramtypes', parentTarget);
var parentPropMetadata = Reflect.getMetadata('propMetadata', parentTarget);
var parentParameters = Reflect.getMetadata('parameters', parentTarget);
var parentAnnotation = parentAnnotations[0];
Object.keys(parentAnnotation).forEach(key => {
if (isPresent(parentAnnotation[key])) {
if (!isPresent(annotation[key])) {
annotation[key] = parentAnnotation[key];
}
}
});
// Same for the other metadata
var metadata = new ComponentMetadata(annotation);
Reflect.defineMetadata('annotations', [ metadata ], target);
};
};
Refer: https://medium.com/@ttemplier/angular2-decorators-and-class-inheritance-905921dbd1b7