Angular2 and support for class inheritance

I am creating an Angular2 application in Typescript and would like to use the class system functionality (read: class inheritance) offered by Typescript. However, it seems that Angular2 does not play well with derived classes. I am looking for some help with my application.

The problem I am facing is that I have a base class and output some child classes. When I create my component tree, I would like to have access to the parent / child components of the components (this is good anyway). As far as I understand, Angular2 offers two options:

  • Insert parent element in child component
  • Use ContentChildren (or ViewChildren) to access the children of the component.

Both work fine if you know the type of the class you're working with (ChildComponent), but don't seem to work when you try to use the base class of these components (BaseComponent) as a selector.

To visualize it in some code (see this Plunker for a live demo), I have an application component / class as follows:

@Component({ selector: 'my-app', template: `<parent-comp> <child-comp1></child-comp1> <child-comp1></child-comp1> <child-comp2></child-comp2> </parent-comp>`, directives: [ParentComponent, ChildComponent1, ChildComponent2] }) export class MyApplication { } 

The base class and child classes are defined as:

 export class BaseComponent { // Interesting stuff here } @Component({ selector: 'child-comp2', template: '<div>child component #2</div>' }) export class ChildComponent2 extends BaseComponent { } @Component({ selector: 'child-comp1', template: '<div>child component #1</div>' }) export class ChildComponent1 extends BaseComponent { } 

And the parent class has its own logic for counting its children.

 @Component({ selector: 'parent-comp', template: `<div>Hello World</div> <p>Number of Child Component 1 items: {{numComp1}} <p>Number of Child Component 2 items: {{numComp2}} <p>Number of Base Component items: {{numBase}} <p><ng-content></ng-content> ` }) export class ParentComponent implements AfterContentChecked { @ContentChildren(ChildComponent1) contentChild1: QueryList<ChildComponent1> @ContentChildren(ChildComponent2) contentChild2: QueryList<ChildComponent2> @ContentChildren(BaseComponent) contentBase: QueryList<BaseComponent> public numComp1:number public numComp2:number public numBase:number ngAfterContentChecked() { this.numComp1 = this.contentChild1.length this.numComp2 = this.contentChild2.length this.numBase = this.contentBase.length } 

(Again, you can see the live demo here )

The output for the first two counters will be as expected. There are 2 ChildComponent1 and 1 ChildComponent2 children. Unfortunately, the BaseComponent counter does not display the sum of these counters, but displays 0. It does not find the BaseComponent class in the child classes.

The same thing happens when a ParentComponent is also distributed from BaseComponent, and you want to embed it in a ChildComponent. An injector will require a specific type of ParentComponent and cannot work with a base class.

Any tips on how to work with derived classes in Angular2? Am I missing something or trying to do something impossible?

+30
angular
Mar 17 '16 at 14:34
source share
2 answers

Add a provider to each derived component by superimposing the base component on the derived component:

 @Component({ selector: 'child-comp2', template: '<div>child component #2</div>', providers: [{provide: BaseComponent, useExisting: forwardRef(() => ChildComponent2) }] }) export class ChildComponent2 extends BaseComponent { } @Component({ selector: 'child-comp1', template: '<div>child component #1</div>', providers: [{provide: BaseComponent, useExisting: forwardRef(() => ChildComponent1) }] }) export class ChildComponent1 extends BaseComponent { } 

Plunker: http://plnkr.co/edit/5gb5E4curAE2EfH2lNZQ?p=preview

+31
May 05 '16 at 2:44
source share

You can use local template variables with the ContentChildren request to create a list of all components with a common base class. Below is the plunk code for the code below. This approach was taken from a proposal by Kara Erickson Blog Newbie Errors .

In the template, each child component is labeled #child :

  <app-container> <app-child1 #child></app-child1> <app-child1 #child></app-child1> <app-child1 #child></app-child1> <app-child1 #child></app-child1> <app-child2 #child></app-child2> </app-container> 

This can then be used to select all components with a common base component:

  import { Component, QueryList, ContentChildren, ViewChildren, AfterViewInit, AfterContentInit } from '@angular/core'; import { BaseComponent } from '../base/base.component'; import { Child1Component } from '../child1/child1.component'; import { Child2Component } from '../child2/child2.component'; @Component({ selector: 'app-container', templateUrl: './src/container/container.component.html' }) export class ContainerComponent implements AfterContentInit { @ContentChildren('child') allChildren: QueryList<BaseComponent>; @ContentChildren(Child1Component) child1Chdilren: QueryList<Child1Component>; @ContentChildren(Child2Component) child2Chdilren: QueryList<Child2Component>; constructor() { } ngOnInit() { } ngAfterContentInit() { } } 
0
Jun 13 '17 at 3:10
source share