How to extend / inherit components?

后端 未结 12 814
萌比男神i
萌比男神i 2020-12-02 04:11

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

相关标签:
12条回答
  • 2020-12-02 05:04

    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!

    0 讨论(0)
  • 2020-12-02 05:04

    Dare I tack on yet another solution? Yes.

    This may not be the answer you're hoping for, but it is a solution.

    npm install vue
    
    Work Cited

    Vue

    0 讨论(0)
  • 2020-12-02 05:07

    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.

    0 讨论(0)
  • 2020-12-02 05:09
    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);
            }
    }
    
    0 讨论(0)
  • 2020-12-02 05:13

    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.

    0 讨论(0)
  • 2020-12-02 05:14

    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

    0 讨论(0)
提交回复
热议问题