99

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.

SternK
  • 11,649
  • 22
  • 32
  • 46
jvinyard
  • 1,071
  • 1
  • 8
  • 9
  • 1
    Try updating your lib to Angular 6, this version include lib creation support. https://github.com/angular/angular-cli/wiki/stories-create-library – Danny908 Jul 23 '18 at 19:46
  • 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. – jvinyard Jul 23 '18 at 20:25
  • Have you checked your package versions? Seems from [This GitHub Issue](https://github.com/angular/material2/issues/10586) others have reported the same error as you – Narm Jul 23 '18 at 20:29

17 Answers17

177

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

sandrooco
  • 8,016
  • 9
  • 48
  • 86
dav1d
  • 2,096
  • 1
  • 13
  • 10
  • 1
    Great it worked for me. Additionally for me this issue comes only when we run `ng serve` without --prod flag. – Amitesh Jun 11 '19 at 08:57
  • 1
    I was looking for the solution for over one day. This works for me at the end! Thanks! – MrHIDEn Jul 07 '20 at 10:14
  • 18
    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. – rslemos Sep 03 '20 at 13:21
  • 1
    thank you very much! This should be marked as solution. – julianpoemp Jun 14 '21 at 08:20
  • 2
    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. – Ondra Koupil Apr 05 '22 at 14:41
  • In my case I also needed to add `preserveSymlinks: true` in angular.json under `projects.$name.architect.test.options`. – peregrination Jun 20 '23 at 14:25
30

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

cheseaux
  • 5,187
  • 31
  • 50
21

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)

Galahad
  • 313
  • 2
  • 6
  • 3
    Ah Thank god man, I was facing this since yesterday, & this helped me – HariHaran Aug 24 '22 at 05:41
  • 2
    Man do I ever owe you a beer. Thanks! – Josh Sullivan Jun 14 '23 at 00:33
  • 1
    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. – lagugula Jul 28 '23 at 14:54
14

I had the same error.

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

Hope that helps!

Sangwin Gawande
  • 7,658
  • 8
  • 48
  • 66
user10161436
  • 149
  • 3
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://stackoverflow.com/a/68718393/217408

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.

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
6

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.

  • 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. – Ovi Trif Apr 30 '22 at 15:48
4

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

HariHaran
  • 3,642
  • 2
  • 16
  • 33
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.

Shabbir Ismail
  • 278
  • 2
  • 14
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"
  }
}
Lars Gyrup Brink Nielsen
  • 3,939
  • 2
  • 34
  • 35
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 {}
Gerros
  • 688
  • 11
  • 20
1

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.

Balduraan
  • 46
  • 2
  • 7
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.

Matt Walterspieler
  • 2,073
  • 2
  • 21
  • 34
0

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

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();
Dharman
  • 30,962
  • 25
  • 85
  • 135
MR-DS
  • 92
  • 3
0

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

Dharman
  • 30,962
  • 25
  • 85
  • 135
V. Nogueira
  • 103
  • 1
  • 4
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.

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.