Extending Angular 2 functionality from a parent component

As a continuation of the discussion on Angular2 and class inheritance support here on SO, I have a question:

Check out my plunckr example: http://plnkr.co/edit/ihdAJuUcyOj5Ze93BwIQ?p=preview

Here is what I am attempting to achieve:

I want to implement some shared functionality that all my components will need to utilize. According to the answers in the aforementioned thread, this can be done.

My specific query is: Is it possible to inject dependencies into the base-component? In my plunker demo, the declared dependency (FormBuilder) appears undefined when logged to the console.

import {AfterContentChecked, Component, ContentChildren, Input, QueryList, forwardRef, provide, Inject} from '@angular/core';
import { FormGroup, FormControl, Validators, FormBuilder, REACTIVE_FORM_DIRECTIVES } from '@angular/forms';



@Component({
  providers: [FormBuilder]
})
export class BaseComponent {
  // Relevant code here
  @Input() id: string;

  constructor(formBuilder: FormBuilder){
    console.log(formBuilder);
    console.log('inside the constructor');
  }


}

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


}

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


}

@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>
   <p>Base Components:</p>
   <ul>
    <li *ngFor="let c of contentBase">{{c.id}}</li>
   </ul>
  `
})
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
  }
}

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

}

Answer №1

To achieve this in Angular2, you cannot simply rely on annotations from the parent component as Angular2 only looks at the annotations of the current component and not those above it.

However, there is a workaround where you can make use of inheritance to inherit annotations from the parent component:

export function Inherit(annotation: any) {
  return function (target: Function) {
    var parentTarget = Object.getPrototypeOf(target.prototype).constructor;
    var parentAnnotations = Reflect.getMetadata('design:paramtypes', parentTarget);

    Reflect.defineMetadata('design:paramtypes', parentAnnotations, target);
  }
}

You can implement this by using the `@Inherit()` decorator like so:

@Inherit()
@Component({
  (...)
})
export class ChildComponent1 extends BaseComponent {
  constructor() {
    super(arguments);
  }
}

For more information on this topic, refer to the following question:

  • Angular2 use imported libs from base class

If you want to understand the inner workings of this approach, check out this article:

Keep in mind that directly manipulating annotations may have limitations, especially with offline compilation and IDE component introspection.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Angular 4 file upload verification: Ensuring safe and secure uploads

Is there a recommended method to validate the file type when uploading a file in an Angular 4 form? Are there any simple ways to accomplish this task? ...

The specified 'Promise<Modules>' type argument cannot be assigned to the parameter of type '(params: any) => Promise<Modules>' in the current context

Looking for some help with this helper function that I need to call, it has the following signature: export const fetchPaginated = async <T>( callback: (params: any) => Promise<T>, { page = 1, pageSize, }: { page?: number; page ...

Is it possible to use Firebase auth.user in order to retrieve the signed-in user directly?

As I develop a webapp with NextJS v13.4 and firebase as my backend using the firebase web modular api, I came across a statement in the documentation: "The recommended way to get the current user is by setting an observer on the Auth object." ...

What is the best way to create props that can accommodate three distinct types of functions in TypeScript?

I have been encountering a problem with the last function in my props interface that is supposed to support 3 different types of functions throughout the application. Despite adding parentheses as requested, I am still facing errors. // In Parent compon ...

What is the process for including a new item in the p-breadcrumb list?

Having trouble getting my code to add a new item to the p-breadcrumb list on click. Any assistance would be greatly appreciated. Thank you in advance! Check out the live demo here ngOnInit() { this.items = [ {label: 'Computer'}, ...

Increase the totalAmount by adding the product each time

Can someone help me understand why the totalAmount shows as 20 when I add a product? Also, why doesn't it increase when I try to increment it? Any insights would be appreciated. Thank you. ts.file productList = [ { id: 1, name: 'Louis ...

Guide to customizing action button color on MatSnackbar?

Currently, I am encountering an issue with the snackbar in my Angular 9 project. Despite adding CSS styles to both the component.scss file and the global style.scss file, the action button on the snackbar displays the same background and text color. In an ...

Is there a way to create a type interface that points to the structure of another type?

I am focused on developing a type interface that includes properties defined in another interface. Below is the schema definition for a model object in TypeScript: export interface ModelSchema { idAttribute: string; name: string; attributes: { ...

making GET and POST requests within a single function using Angular 2

How can I trigger an HTTP POST service call after a successful GET response? This is how I've implemented the GET call: import {Page, NavController} from 'ionic-angular'; import {Http, Headers} from 'angular2/http'; import ' ...

String interpolation can be used to easily accept numbers with dot separators

Is it possible to create a function that can accept numbers with dot separators? Here are some examples: func('100.000.002.333') // should pass func('10') // should pass func('20') // should pass func('100') // shou ...

Angular4: Automatically disable button after it is clicked within ngFor loop

I am facing the issue of disabling a <button> in an ngFor loop after it has been clicked by the user. Each button corresponds to an element in the loop, so I need to distinguish them using separate boolean values. Below is a snippet of the HTML code ...

Having trouble deploying Firebase Cloud function following the migration to Typescript

After following the steps outlined in the firebase documentation to convert my cloud functions project to TypeScript (see https://firebase.google.com/docs/functions/typescript), I encountered an error when attempting to deploy using 'firebase deploy - ...

Having trouble clicking on a button with Protractor because the button text is located within a child span element

Having trouble clicking a button with protractor. The DOM structure is displayed in the image above. Here are some of the locators I've attempted to use: element(by.xpath("(//div[@class='mat-drawer-backdrop ng-star-inserted'])//a followin ...

Transferring information from a child to parent component within Angular using the <router-outlet> component

I currently have the following code in my app.component.html file: <div> <app-login (un)="doSth($event)"></app-login> </div> <router-outlet (un)="doSth($event)"></router-outlet> And in my app.com ...

Enhancing User Experience through 'Remember Me' Feature in Angular App

I need assistance with adding the Remember Me functionality to a login form in an Angular application. Could someone please provide guidance on how to achieve this? Your help would be highly appreciated! Thank you in advance! Below is my login.ts file: ngO ...

How can I refresh the information in the navbar in Angular2?

Looking for guidance on the following scenario: I am working with two distinct components called navbar and homepage. The navbar has a specific area designated for displaying the city name. Within the homepage component, there is a form that includes a ...

Ensure there is a gap between each object when they are arranged in a

Is there a way to customize the layout of elements in the ratings view so that there is automatic spacing between them? I considered using text (white spaces) for this purpose, but it seems like an inefficient solution. Are there any other alternatives to ...

Create a single datetime object in Ionic (Angular) by merging the date and time into a combined string format

I have a string in an ionic project that contains both a date and time, and I need to merge them into a single datetime object for sending it to the server const date = "Fri Jan 07 2022 13:15:40 GMT+0530 (India Standard Time)"; const time = " ...

Encountering an issue with TS / yarn where an exported const object cannot be utilized in a consuming

I am currently working on a private project using TypeScript and Yarn. In this project, I have developed a package that is meant to be utilized by one or more other applications. However, as I started to work on the consumer application, I encountered an ...

Issue encountered when attempting to render a fully dynamic table with an empty object

I'm looking to dynamically generate a table with headers, rows, and cells based on JSON data retrieved from an API call. The data being fetched from the API is in the form of a dataframe. Here is a sample of the JSON'd dataframe (as seen in the ...