What is the process for disabling dependency injection in an Angular component?

My Angular component serves as a superclass and is never instantiated on its own. There are multiple components that extend this one, each operating on different data types, so the superclass utilizes generic typing.

In addition to this, the superclass must be able to create objects of the provided type. Therefore, you can see that the constructor of the component takes a parameter to define a constructor for the generic type.

@Component({
  selector: 'my-component',
  templateUrl: './my-component.component.html'
})
export class MyComponent<Class1> implements OnInit {

    public object!:Class1;

    constructor(protected type1 : new () => Class1) { 
        this.object = new this.type1();
    }

}

It's important to note that when the subclass component calls super(), it always provides the actual type (e.g. MyClass), ensuring the component has access to it.

An essential point to highlight is that this setup works perfectly fine. When I use `ng serve`, the generic type is passed from the subclass component, and the entire page functions correctly as intended.

I'm now working on transforming this generic component into a library package for broader usage. However, I face an issue during the build process where I receive the error message: "error NG2003: No suitable injection token for parameter 'type1' of class 'MyComponent'."

The Angular compiler mistakenly believes it needs to inject something into that constructor parameter, even though I have no need for this. How can I disable this behavior so that the compiler allows me to build and pass the constructor argument as I already know how to do?

Answer №1

Avoid using the @Component decorator on the superclass; instead, apply it to the specific components that inherit from this class.

You can also consider creating an Injection Token for the type function and then provide it from the child classes.

// Update your typings and utilize them rather than 'any' type
export const TYPE_INJECTION_TOKEN = new InjectionToken<new () => any>(
  'TYPE_INJECTION_TOKEN'
);

// Should this actually be a directive? Is there a need to call it explicitly?
@Component({
  selector: 'my-component',
  templateUrl: './my-component.component.html'
})
export class MyComponent {
  public object;

  constructor(_injector: Injector) {
    const factory = _injector.get(TYPE_INJECTION_TOKEN);

    this.object = new factory();
  }
}

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  providers: [
    {
      provide: TYPE_INJECTION_TOKEN,
      useValue: function () {}, // This serves as the constructor function
    },
  ],
})
export class AppComponent extends MyComponent {
  constructor(_injector: Injector) {
    super(_injector);
  }
}

Answer №2

I decided to award the individual above with the check because their response aligned perfectly with my query. Although, as mentioned by some commentators, it falls short when dealing with a scenario where a component superclass requires Angular features (such as @ViewChild). Given that I utilize Angular features in my work, I had to come up with an alternative resolution:

constructor(@Inject(null) protected type1 : new () => Class1) 
{ 
    this.object = new this.type1();
}

It appears that @Inject(null) is adequate in indicating to Angular not to perform any injections, resulting in the compiler no longer generating errors.

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

Is there a function return type that corresponds to the parameter types when the spread operator is used?

Is it possible to specify a return type for the Mixin() function below that would result in an intersection type based on the parameter types? function Mixin(...classRefs: any[]) { return merge(class {}, ...classRefs); } function merge(derived: any, ... ...

What is causing certain code to be unable to iterate over values in a map in TypeScript?

Exploring various TypeScript idioms showcased in the responses to this Stack Overflow post (Iterating over Typescript Map) on Codepen. Below is my code snippet. class KeyType { style: number; constructor(style) { this.style = style; }; } fu ...

What sets aws-cdk-lib apart from @aws-cdk/core, @aws-cdk/aws-iam, and others?

There seems to be a variety of examples out there using the AWS CDK, with some referencing aws-cdk-lib and others using @aws-cdk/core. Can someone clarify the distinction between these two and provide guidance on when to use one over the other? ...

Guard against an array that contains different data types

I am trying to create a guard that ensures each entry in an array of loaders, which can be either query or proxy, is in the "success" state. Here is my attempted solution: type LoadedQueryResult = Extract<UseQueryResult, { status: 'success' }& ...

Executing a for loop concurrently by utilizing async/await promises

In my current code, I am using a for loop structured like this: async myFunc() { for (l of myList) { let res1 = await func1(l) if (res1 == undefined) continue let res2 = await func2(res1) if (res2 == undefined) continue ...

Is it possible to create two subclasses where the methods return the types of each other?

I am faced with a situation where I have two classes that rely on each other's methods: class City { (...) mayor(): Person { return this.people[0]; } } class Person { (...) birthCity(): City { return this.cities.birth; } } ...

JavaScript - Persistent memory retention issues

I've noticed persistent memory leaks in my TypeScript application (3PG), leading me to believe there's an issue with memory management. Comparison of Applications: 2PG -> https://github.com/theADAMJR/2pg [no memory leaks] 3PG -> the speci ...

How to implement dependency injection in CompositeControl with Ninject

Is there a way to inject dependency into a CompositeControl in C#? I attempted the following approach, but MyServerControl's Calculate property is still null. Any suggestions or guidance would be greatly appreciated! public class MyServerControl : ...

What is the best way to trigger an API call whenever a variable is updated?

Below is the code I currently have to update myVariable: private dataSubscription: Subscription; myVariable: number; this.dataSubscription = this.mydata.onReply$.subscribe((data: any) => { this.myVariable = data.id; }); Now, I would like to trigg ...

There is no overload that matches this call in Next.js/Typescript

I encountered a type error stating that no overload matches this call. Overload 1 of 3, '(props: PolymorphicComponentProps<"web", FastOmit<Omit<AnchorHTMLAttributes, keyof InternalLinkProps> & InternalLinkProps & { ...; ...

Both radio buttons are being chosen simultaneously

<div class="container"> <div class="row"> <form> <div class="form-group"> <label>username</label> <br /> <input type="text" class=" ...

Embarking on a fresh XR experience

As a newcomer to TypeScript, I am exploring how to create a functionality similar to a "double-click" event for a hand-input controller in my Three.js application. Here is my approach: - I monitor a click event - I check the timing between the last click ...

What is the best way to enforce input requirements in Typescript?

I am currently facing an issue with two required inputs that need to be filled in order to enable the "Add" button functionality. I have considered using *ngIf to control the visibility of the button based on input values, but it seems to not be working. ...

The drop down list does not support the 'click' function and is throwing a TypeError

Could someone please assist in troubleshooting my code? I am trying to select a specific value from a dropdown list but is encountering difficulties. The code is able to retrieve the values from the dropdown but is unable to successfully click on the mat ...

What is the method for adjusting the time format?

Using the TIME data type, my data is currently displayed in the format hh:mm:ss (03:14:00). How can I change it to display in the format hh:mm (03:14)? The usual DATE type method does not seem to work: {{test.time | date: 'HH:mm'}} However, thi ...

Application suddenly crashes due to a severe issue: FATAL EXCEPTION: java.lang.RuntimeException, preventing the activity from starting

I recently updated my Ionic, Angular, and Capacitor application to the latest versions - Ionic 7, Angular 16, and Capacitor 5. After the update, I noticed that on Android, the app works fine when installed for the first time. However, upon restarting the a ...

Encountering a surprise token < while processing JSON with ASP.NET MVC alongside Angular

I encountered an issue when attempting to return the Index page. The data is successfully sent from the client to the server, but upon trying to display the Index page, an error occurs. Could someone review my code and identify where the mistake lies? acc ...

Angular 5: Sharing a Singleton Service Across Components in a Lazily Loaded Feature Module

I'm currently utilizing Angular 5 and have implemented a feature module with routing that is configured for lazy loading. I have reached a point where I need to share a single instance of a service, located within the feature module, between two compo ...

Enhancing the appearance of div content in Angular by utilizing local template variables and material elements

Within this particular implementation, I have utilized an md-sidenav component with a local template variable #sidenavsearchArea. <md-sidenav #sidenavSearchArea align="" mode="push" opened="false"> sidenav content here.. </md-siden ...

What is the process for defining the type of the context for an Apollo resolver?

I am facing an issue with my Apollo GraphQL subgraph where I need to define the type for the context argument in my resolvers. When creating a resolver, I tried setting the context type like this: interface Context { dataSources: { shopify: Shopify; ...