inject() must be called from an injection context
AngularTypescriptAngular Problem Overview
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.
Angular Solutions
Solution 1 - Angular
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
Solution 2 - Angular
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
Solution 3 - Angular
I had the same error.
I found that I was importing Inject
from @angular/core
instead of @angular/core/testing
.
Hope that helps!
Solution 4 - Angular
Same issue but my case was dumber...
I had npm install something
in the wrong folder.
So just rm the wrong "node_modules" and npm install in the good folder x)
Solution 5 - Angular
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://stackoverflow.com/a/68718393/217408
A publishable package
- must not have
dependencies
, onlypeerDependencies
npm install
should not be run. The library must not contain anode_modules
directory.
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.
Solution 6 - Angular
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.
Solution 7 - Angular
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"
}
}
Solution 8 - Angular
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 {}
Solution 9 - Angular
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.
Solution 10 - Angular
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.
Solution 11 - Angular
If the error appears on Karma with tests, just delete de node_modules folder and install again.
Solution 12 - Angular
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();
Solution 13 - Angular
I found that I was importing Inject from @angular/core instead of @angular/core/testing.