inject() must be called from an injection context
Asked Answered
W

17

106

I am trying to export my Angular app as an npm module to be consumed by other applications, but am running into some difficulties. I have not been able to find this error anywhere else on the internet, and am at my wit's end.

I followed this tutorial: https://medium.com/@nikolasleblanc/building-an-angular-4-component-library-with-the-angular-cli-and-ng-packagr-53b2ade0701e

I used ng-packagr to export my app as an npm module. I can successfully install it from a local folder on a barebones test app, but cannot get it to display my app.

Error:

    AppComponent.html:1 ERROR Error: inject() must be called from an injection context
    at inject (core.js:1362)
    at ChangeStackService_Factory (template-wiz.js:2074)
    at _callFactory (core.js:8223)
    at _createProviderInstance (core.js:8181)
    at resolveNgModuleDep (core.js:8156)
    at NgModuleRef_.push../node_modules/@angular/core/fesm5/core.js.NgModuleRef_.get (core.js:8849)
    at resolveDep (core.js:9214)
    at createClass (core.js:9094)
    at createDirectiveInstance (core.js:8971)
    at createViewNodes (core.js:10191)

template-wiz.module.ts (Module being exported)

    import { NgModule, ChangeDetectorRef, ComponentFactoryResolver } from '@angular/core';
    import { TemplateWizComponent } from './template-wiz.component';
    import { BrowserModule } from '@angular/platform-browser';
    import { FormsModule } from '@angular/forms';
    import { HttpClientModule } from '@angular/common/http';
    import { BlockListDirective } from './Directives/block-list.directive';
    import { TemplateItemsDirective } from './Directives/template-items.directive';
    import { ContextMenuComponent, SeperatorComponent, DragBoxComponent, SnapLineComponent, PropertiesComponent, ToolboxComponent } from './Components'
    import { AddressBlockComponent, TextBlockComponent, ImageBlockComponent, DataBlockComponent } from './Data-Blocks';
    import { BlockFactoryService, BlockRegistryService, DisplayInfoService, MouseClickService, SavingService, SnapService, TextHelperService, UserModeService } from './Services';
    import { PageContextMenuComponent } from './Components/page-context-menu/page-context-menu.component';
    import { CamelToWordsPipe } from './Pipes/camel-to-words.pipe';
    import { PdfPublisherService } from './Services/pdf-publisher/pdf-publisher.service';
    import { GradientBlockComponent } from './Data-Blocks/gradient-block/gradient-block.component';
    import { PropToTypePipe } from './Pipes/prop-to-type.pipe';
    import { ShapeBlockComponent } from './Data-Blocks/shape-block/shape-block.component';
    import { CommonModule } from '@angular/common';
    import { ModuleWithProviders } from '@angular/compiler/src/core';


    @NgModule({
      imports: [
        CommonModule,
        FormsModule,
        HttpClientModule
      ],
      entryComponents: [
        AddressBlockComponent,
        ContextMenuComponent,
        DragBoxComponent,
        GradientBlockComponent,
        ImageBlockComponent,
        PageContextMenuComponent,
        SeperatorComponent,
        ShapeBlockComponent,
        SnapLineComponent,
        TextBlockComponent
      ],
      declarations: [
        TemplateWizComponent,
        DataBlockComponent,
        AddressBlockComponent,
        SeperatorComponent,
        BlockListDirective,
        TemplateItemsDirective,
        ImageBlockComponent,
        TextBlockComponent, DragBoxComponent,
        SnapLineComponent,
        ToolboxComponent,
        PropertiesComponent,
        ContextMenuComponent,
        PageContextMenuComponent,
        GradientBlockComponent,
        CamelToWordsPipe,
        PropToTypePipe,
        ShapeBlockComponent
      ],
      providers: [
        BlockFactoryService,
        BlockRegistryService,
        DisplayInfoService,
        MouseClickService,
        SavingService,
        SnapService,
        TextHelperService,
        UserModeService,
        PdfPublisherService
      ],
      //bootstrap: [TemplateWizComponent],
      exports: [
        TemplateWizComponent
      ]
    })
    export class TemplateWizModule {
      static forRoot(): ModuleWithProviders {
        return {
          ngModule: TemplateWizModule,
          providers: [
            ComponentFactoryResolver
          ]
        }
      }
    }

app.module.ts (Bare bones test app using my module)

    import { BrowserModule } from '@angular/platform-browser';
    import { NgModule } from '@angular/core';
    import { FormsModule } from '@angular/forms';
    import { HttpClientModule } from '@angular/common/http';
    import { AppComponent } from './app.component';
    import { TemplateWizModule } from 'template-wiz';

    @NgModule({
      declarations: [
        AppComponent,
      ],
      imports: [
        BrowserModule,
        FormsModule,
        TemplateWizModule.forRoot(),
        HttpClientModule
      ],
      providers: [],
      bootstrap: [AppComponent]
    })
    export class AppModule { }

Any help or pointers at all would be appreciated, thank you.

Willem answered 23/7, 2018 at 19:22 Comment(3)
Try updating your lib to Angular 6, this version include lib creation support. github.com/angular/angular-cli/wiki/stories-create-libraryDismay
Thank you for the tip, this project was written in angular 6. I was hoping to avoid having to turn the app into a library, but it may be unavoidable.Willem
Have you checked your package versions? Seems from This GitHub Issue others have reported the same error as youDisallow
N
197

There seems to be an issue when using npm link when consuming the library.

Solution: use projects.$name.architect.build.options.preserveSymlinks: true in the angular.json file of the client project, not the library.

Further information: https://github.com/angular/angular/issues/25813

Nonchalance answered 12/2, 2019 at 9:58 Comment(9)
Great it worked for me. Additionally for me this issue comes only when we run ng serve without --prod flag.Treiber
I was looking for the solution for over one day. This works for me at the end! Thanks!Keto
Life saving. I would never try preserveSymlinks for a "inject() must be called from an injection context" error. Just to make it clear: the change is to be made on the client project, not the lib project.Jakoba
thank you very much! This should be marked as solution.Unmusical
Also I bumped into this issue twice. In one case, preserveSymlinks helped. In the other case the problematic package was not symlinked, but installed classically via npm. The problem was that it was built with different version of Angular than the client app. One can easily check if it is the cause - in client app's node_modules, the folder with the library package contained another node_modules with its own version of Angular.Jacquetta
In my case I also needed to add preserveSymlinks: true in angular.json under projects.$name.architect.test.options.Vaulting
The comment from @Jakoba is very crucial! Thanks!Trever
this was the solution that solved my problem. thanks so much!Astromancy
Can't believe this was it as well. I used npm link for development/debugging purposes, probably like most people here, and the error is just nonsensical with regards to that. Thanks for the solution!Clair
B
33

Here's what solved it for me :

Add the following line in tsconfig.app.json under compilerOptions :

"paths": { "@angular/*": [ "../node_modules/@angular/*" ] }

Source : https://github.com/angular/angular/issues/25813#issuecomment-500091900

Boehmenism answered 14/5, 2020 at 15:52 Comment(11)
This definitely worked for me with Webpack v4.43.0 and Angular v8.2.14.Shallot
Worked with anguler 10Installation
Not working for me in Angular 11 linking a generated client. See #65710451Murther
I can confirm this solved the issue for me in Angular 12Hardnett
I can confirm as well that this resolved my issue after updating from ng11 to ng12Give
This works but you need to edit the path to target your current node_modules directory relative to the tsconfig fileMob
Thanks for the link @StefanFalk https://mcmap.net/q/205442/-getting-quot-inject-must-be-called-from-an-injection-context-quot-after-upgrading-to-angular-11 was what I had wrong.Hannover
Worked in Angular 13 for me. This never was a problem for Angular 11 and 12 though.Tragacanth
That did work for me, however with one dot instead of two (./node_modules/...), seen at github.com/angular/angular/issues/25813#issuecomment-584866010Icelander
If it helps, i have library -> application setup. I had to do this in both application and library. NOT JUST IN LIBRARYSexology
Works in angular 15Siobhansion
S
26

Same issue but my case was dumber...

I ran npm install something in the wrong folder.

So just remove the wrong "node_modules" and npm install in the correct folder x)

Swanson answered 7/5, 2021 at 8:7 Comment(3)
Ah Thank god man, I was facing this since yesterday, & this helped meMatrices
Man do I ever owe you a beer. Thanks!Phyllis
All hail to the savior :) thank you man. I was having a problem with ngx-paypal throwing this error from inside. I would never find this without you. Actually, I had multiple projects in the wrong folder, so thank you very much.Aesthesia
D
14

I had the same error.

I found that I was importing Inject from @angular/core instead of @angular/core/testing.

Hope that helps!

Dribble answered 31/7, 2018 at 15:32 Comment(3)
I ended up switching it into a component library in Angular 6, and it ended up working much better. Would recommend the same to anyone else. Thank you for the insight howeverWillem
I was unit testing and this answer solved my problemTallowy
Devil is in the details :)Perturbation
W
10
I my case it was because this code was missing in `test-setup.ts`. I had only the first 2 lines.
import 'jest-extended';
import 'jest-preset-angular/setup-jest';

import { getTestBed } from '@angular/core/testing';
import {
  BrowserDynamicTestingModule,
  platformBrowserDynamicTesting,
} from '@angular/platform-browser-dynamic/testing';

getTestBed().resetTestEnvironment();
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), {
  teardown: { destroyAfterEach: false },
});

What made it a bit difficult was that I got a different unhelpul error even after adding this code because it was an Angular library package with its own package.json where the dependency @angular/platform-browser-dynamic was missing.

Above helped, but I removed this code again.
What actually helped was https://mcmap.net/q/205442/-getting-quot-inject-must-be-called-from-an-injection-context-quot-after-upgrading-to-angular-11

A publishable package

  • must not have dependencies, only peerDependencies
  • npm install should not be run. The library must not contain a node_modules directory.

It was confusing that having dependencies and node_modules worked fine since months, but suddenly started failing and now even older commits don't work anymore without fixing above points.

Winsome answered 4/1, 2022 at 11:42 Comment(1)
This is what worked for me, remove the node_modules and explicit dependencies from the library project.Buckshot
G
8

I ran in a similar problem. Using a angular lib within an angular app with npm link.

As mentioned: "Solution: use projects.$name.architect.build.options.preserveSymlinks: true in the angular.json file of the client project, not the library." works when serving the appliction with "ng serve".

However the error still was there when unit testing the application with "ng test". Adding preserveSymLinks in the the angular.json file here:

projects.$name.architect.test.options.preserveSymlinks: true

fixed that as well.

Gerrit answered 15/2, 2022 at 10:21 Comment(1)
Thanks a lot for explaining this! I had a similar scenario with using a local @ncstate/sat-popover that I adapted for Angular 13 since their official repo doesn't yet support Angular13.Milligan
M
6

Update 2022

I was facing this problem in a Angular Library workspace. My directory structure looks like this

project
│   package.json
│
└───projects
│   │
│   └─── myLibApp
│       │   file111.txt
│       │   file112.txt
│       │   ...
│   
└─────── myLibExampleApp

I wanted to add some dependencies to my main library and I did npm i inside the myLibApp folder caused this problem. I had to remove the node_modules inside the lib & provide dependencies both in root level package.json as well as inside the lib but do npm i only in the root.

Also ended up here

Matrices answered 24/8, 2022 at 6:21 Comment(2)
Life saving! God bless you!Innoxious
thank you a lot @Matrices , it was exactly this issue and no one in the internet specified this hint! you are a life saver <3 , I guess this answer should be voted with a lot of points ! :)Clipping
C
2

Same issue here

My Case: When I was using Mat Dialog

import { Component, OnInit, Inject } from '@angular/core';

 constructor(
    @Inject(MAT_DIALOG_DATA) public data: any,
    public matDialogRef: MatDialogRef<MatConfirmDialogComponent>) { }

inject & Inject are different:

inject is a function and Inject is Interface

I hope this helps someone who comes finding the same scenario.

Cubical answered 26/9, 2019 at 16:25 Comment(0)
O
2

For everyone that runs into this problem and uses Angular Universal and a custom Angular Library linked with npm link:

The mentioned solution to add preserveSymlinks to your angular.json projects.$name.architect.build.options.preserveSymlinks: true is missing two parts.

For dev:ssr or serve:ssr to work, you need to add it aditionaly here: projects.$name.architect.server.options.preserveSymlinks: true

And as mentioned in another comment, If you use tests, don't forget it here: projects.$name.architect.test.options.preserveSymlinks: true

If there is yet another use case / location not listed here, comment it below.

Openhanded answered 19/7, 2022 at 12:13 Comment(0)
W
1

I got the error message inject() must be called from an injection context when I was creating a tree-shakable InjectionToken that used another InjectionToken in its factory, e.g.

import { InjectionToken } from '@angular/core';

import { dependeeToken } from './dependee.token';

export const dependingToken = new InjectionToken<string>('depending', {
  factory: () => inject(dependeeToken) + ' depending';
  providedIn: 'root',
});

Instead, I added a provider for the depending InjectionToken to an NgModule.

import { NgModule } from '@angular/core';

import { dependeeToken } from './dependee.token';
import { dependingToken } from './depending.token';

@NgModule({
  providers: [
    {
      deps: [dependeeToken],
      provide: dependingToken,
      useFactory: dependee => dependee + ' depending',
    }
  ],
})
export class DependingModule {}

package.json excerpt

{
  "dependencies": {
    "@angular/compiler": "6.1.9",
    "@angular/core": "6.1.9"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "0.8.4",
    "@angular/cli": "6.2.4",
    "@angular/compiler-cli": "6.1.9",
    "typescript": "2.9.2"
  }
}
Weaks answered 4/10, 2018 at 13:24 Comment(0)
A
1

What solved it for me was to use the providedIn property in the Injectable decorator instead of registering the service in the app module in the providers for the service which was causing me this error message.

@Injectable({
  providedIn: 'root'
})
export class HeroService {}
Antlia answered 11/2, 2019 at 10:20 Comment(0)
F
0

I had this error when building angular 9.0.0-next.0 with ng build --prod command. Downgrading to version ~8.2.8 made my angular app work again.

It was working well in development with ng serve, so it seems to be linked to Ivy.

Freezedry answered 7/10, 2019 at 13:45 Comment(0)
I
0

If the error appears on Karma with tests, just delete de node_modules folder and install again.

Intervene answered 19/3, 2020 at 14:21 Comment(0)
H
0

I came across a similar problem in testing an Angular application. The application imported a Service that had been installed from @bit with npm. The service depended on the MatSnackBar which seemed to be causing the same error as the OP.

To get the tests to run I instantiated the service when configuring the testing module.

In the example below, the AsyncUIFeedbackService was installed from Bit via npm. Setting the useValue to a new instance of the service, and stubbing the MatSnackBar worked great.

await TestBed.configureTestingModule({
      declarations: [GeneralInfoComponent],
      providers: [
        FormBuilder,
        { provide : AsyncUIFeedbackService, 
          useValue: new AsyncUIFeedbackService({} as MatSnackBar)}, // <----Create the service
      ],
      imports: [AsyncUIFeedbackModule]
    }).compileComponents();
Handlebar answered 15/4, 2021 at 15:28 Comment(0)
A
0

I found that I was importing Inject from @angular/core instead of @angular/core/testing.

Archuleta answered 2/12, 2021 at 21:42 Comment(0)
B
0

Background: this is my own Angular 9 app as I was trying to locally import my own Angular 9 library

My issue was this flag in the tsconfig.json of my own library which I had built locally:

  "angularCompilerOptions": {
    "strictInjectionParameters": true
  }

According to the Angular documentation:

When true, reports an error for a supplied parameter whose injection type cannot be determined. When false, constructor parameters of classes marked with @Injectable whose type cannot be resolved produce a warning. The recommended value is true, but the default value is false.

https://angular.io/guide/angular-compiler-options#strictinjectionparameters

To be honest, I don't know much about that flag beyond that description and can go without it; it was generated in a new project anyways.

Brianbriana answered 18/10, 2022 at 2:10 Comment(0)
A
0

In my case, I mean, I'm working with Angular2 and Firebase Real time Database (rtdb), I get the same error after getting some help from chatGPT, copying some code script and pasting it to my project.

I see a junky line like this private database: Database = inject(Database); and never use it in the project.

After commenting this line, it works. If you inject() something in Angular2, you have to use it. That's it.

Aleph answered 8/6, 2023 at 19:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.