I am facing this error although I have imported MailerModule in app.module and using it in other module named 'user.module'.
Attaching error Image and code
App.Module
import { NodeMailerService } from './mailer/mailer.service';
#Module({
imports: [
MailerModule.forRootAsync({
inject: [AppConfigService],
useFactory: (configService: AppConfigService) => {
const config = configService.smtpEmailObject;
return { ...config }
},
})
})
export class AppModule { }
Users.Module
import { NodeMailerService } from '../mailer/mailer.service';
#Module({
imports: [],
providers: [UsersService, ...userProviders, ...userMetaProviders,NodeMailerService],
exports: [UsersService],
controllers: [UsersController]
})
export class UsersModule { }
Error Image
Create MailerModule, add NodeMailerService to the providers and export NodeMailerService from it. Then import MailerModule in Users.Module and delete NodeMailerService from Users.Module.
Related
I'm trying access a database using a custom provider as per this guide. At startup, Nestjs throws the error Nest can't resolve dependencies of the EventsService (?). Please make sure that the argument DATA_SOURCE at index [0] is available in the AppModule context.
Here are my files
Database providers
import { DataSource } from 'typeorm';
export const databaseProviders = [
{
provide: 'DATA_SOURCE',
useFactory: async () => {
const dataSource = new DataSource({
type: "mysql",
host: "host",
port: 3306,
username: "username",
password: "password",
synchronize: true,
logging: true,
});
return dataSource.initialize();
},
},
];
Database module
import { databaseProviders } from "./database.providers";
import { Module } from "#nestjs/common";
#Module({
providers: [...databaseProviders],
exports: [...databaseProviders],
})
export class DatabaseModule {}
Events service
import { Inject, Injectable } from '#nestjs/common';
import { DataSource } from 'typeorm';
import { DatabaseModule } from './database.module';
import { Event } from './entities/event.entity';
import { EventInvite } from './entities/eventInvite.entity';
#Injectable()
export class EventsService {
constructor(#Inject("DATA_SOURCE") private readonly database: DataSource) { }
createEvent(userId: string, event: Event) {
this.database.manager.create(Event, event)
}
deleteEvent(eventId: string){
this.database.manager.delete(Event, { eventId })
}
}
Events Module
import { Module } from '#nestjs/common';
import { DatabaseModule } from './database.module';
import { EventsController } from './events.controller';
import { EventsService } from './events.service';
#Module({
imports: [DatabaseModule],
controllers: [EventsController],
providers: [EventsService],
exports: [EventsService]
})
export class EventsModule {}
App module
import { Module } from '#nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { EventsController } from './events/events.controller';
import { EventsService } from './events/events.service';
import { EventsModule } from './events/events.module';
import { DatabaseModule } from './events/database.module';
#Module({
imports: [],
controllers: [AppController, EventsController],
providers: [AppService, EventsService],
})
export class AppModule {}
If I import DatabaseModule inside of AppModule everything works. My question is, why is this required? My understanding thus far is that Nestjs builds a dependency tree, which in this case should look something like AppModule => EventService => DatabaseService. AppModule doesn't directly access DatabaseService, and therefore shouldn't need to import it directly, so why is Nestjs failing to resolve this dependency?
that module isn't global, thus its providers aren't globally available. As you're registering the service EventsService again in AppModule, you need to import the DatabaseModule
I believe this is what you're trying to do (which is pretty much what the docs shows):
#Module({
imports: [EventsModule],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
than you won't have 2 instances of EventsService and EventsController anymore, only the one registered in EventsModule module.
I'm trying to export and import a service in NestJS. It seems easy and I thought it should work like this but I got an error saying that Nest can't resolve the dependencies.
SettingsModule
This module has the service that should be imported, and exports it.
#Module({
imports: [
MongooseModule.forFeature([{ name: Setting.name, schema: SettingSchema }]),
],
providers: [SettingsService],
exports: [SettingsService],
})
export class SettingsModule {}
MsgraphModule
This module should import the service through the module because the service is injected in their service.
#Module({
imports: [SettingsModule],
providers: [MsgraphService],
})
export class MsgraphModule {}
AppModule
#Module({
imports: [
MongooseModule.forRoot('mongodb://localhost/lead-import', {
useCreateIndex: true,
}),
MsgraphModule,
SettingsModule,
...
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
What am I doing wrong here?
The problem was that I used the #Inject() decorator which is only needed for custom dependency injections.
#Injectable()
export class MsgraphService {
private client: Client;
private authenticator;
constructor(#Inject() private settingsService: SettingsService) {
this.init();
this.authenticator = new MSGraphAuthenticator();
}
...
}
So removing the #Inject() did the trick.
when I nest start the code, it gives follow error, what is the problem?
I set ConfigModule as Gloabl, so I shouldn't need to import.
If I missed any code, please tell me, I can post it here.
I reference usage in NestJS Jwt package
I previously use JwtModule.register() with hardcoded secrets and options, it works fine.
[Nest] 159128 - 02/27/2021, 6:27:15 PM [ExceptionHandler] Nest cannot create the AuthModule instance.
The module at index [2] of the AuthModule "imports" array is undefined.
Potential causes:
- A circular dependency between modules. Use forwardRef() to avoid it. Read more: https://docs.nestjs.com/fundamentals/circular-dependency
- The module at index [2] is of type "undefined". Check your import statements and the type of the module.
TyprOrmModule access the database just fine, it proves configService picks up environment variables in .env
AppModule.ts:
import { Module } from '#nestjs/common';
import { AppController } from './app.controller';
import { TypeOrmModule } from '#nestjs/typeorm';
import { Connection } from 'typeorm';
import { join } from 'path';
import { UserModule } from './user/user.module';
import { AuthModule } from './auth/auth.module';
import { FormModule } from './form/form.module';
import { InventoryModule } from './inventory/inventory.module';
import { ConfigModule, ConfigService } from '#nestjs/config';
#Module({
imports: [
ConfigModule.forRoot({
isGlobal: true
//, ignoreEnvFile: true
}),
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
useFactory: (configService: ConfigService) => ({
type: 'mysql',
host: configService.get('DB_HOST'),
port: configService.get<number>('DB_PORT'),
username: configService.get('DB_USERNAME'),
password: configService.get('DB_PASSWORD'),
database: configService.get('DB_DATABASE'),
synchronize: true,
autoLoadEntities: true,
}),
inject: [ConfigService],
})
, UserModule, AuthModule, FormModule, InventoryModule,
],
controllers: [AppController],
})
export class AppModule {
constructor(private connection: Connection) { }
}
if I add imports ConfigModule and inject ConfigService, it gives exact error at nest start. I just can't identify where the problem is.
AuthModule.ts:
import { Module } from '#nestjs/common';
import { AuthController } from './auth.controller';
import { LdapStrategy } from './ldap/ldap.strategy';
import { AuthService } from './auth.service';
import { JwtModule } from '#nestjs/jwt';
import { PassportModule } from '#nestjs/passport';
import { jwtConstants } from './jwt/constants';
import { JwtStrategy } from './jwt/jwt.strategy';
import { UserModule } from 'src/user/user.module';
import { JwtRefreshTokenStrategy } from './jwt/jwt.refresh.strategy';
import { ConfigModule, ConfigService } from '#nestjs/config';
#Module({
imports: [
PassportModule,
//ConfigModule,
JwtModule.registerAsync({
//imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({
secret: configService.get<string>('JWT_SECRET'),
// signOptions: {
// algorithm: 'HS256',
// expiresIn: configService.get<number>('JWT_EXPIRES_IN_SEC'),
// }
}),
//inject: [ConfigService],
}),
, UserModule
],
controllers: [AuthController],
providers: [
LdapStrategy
, AuthService
, JwtStrategy
, JwtRefreshTokenStrategy
],
//exports: [AuthService],
})
export class AuthModule { }
Although this answer is pretty late, I ran into the exact same issue and found the solution on the Github site for #nestjs/jwt (https://github.com/nestjs/jwt#async-options). Posting here just in case anyone else runs into it.
It appears that you also need to inject the ConfigService as well.
JwtModule.registerAsync({
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({
secret: configService.get<string>('SECRET'),
}),
inject: [ConfigService],
})
This is my test file and I am trying to identify the error preventing me from running a successful test:
import { async, ComponentFixture, TestBed } from '#angular/core/testing';
import { Component, Directive, Input, OnInit } from '#angular/core';
import { TestComponent } from './test.component';
import { NgbDropdownModule, NgbCollapse } from '#ng-bootstrap/ng-bootstrap';
import { CommonModule } from '#angular/common';
import { Routes } from '#angular/router';
import { RouterTestingModule } from '#angular/router/testing';
import { NO_ERRORS_SCHEMA } from '#angular/core';
import {BrowserDynamicTestingModule, platformBrowserDynamicTesting} from '#angular/platform-browser-dynamic/testing';
let comp: TestComponent;
let fixture: ComponentFixture<MyComponent>;
describe('TestComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ TestComponent ],
providers: [
// DECLARE PROVIDERS HERE
{ provide: TestingCompilerFactory }
]
}).compileComponents()
.then(() => {
fixture = TestBed.createComponent(TestComponent);
comp = fixture.componentInstance;
});
}));
it('should be created', () => {
expect(TestComponent).toBeTruthy();
});
I am getting this error which I guess is because I am not wrapping it correctly.
error TS1005: ';' expected.
But I also get
No provider for TestingCompilerFactory
First fix your syntax error1,2
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [TestComponent],
providers: [{ provide: TestingCompilerFactory }]
})
.compileComponents()
.then(() => {
fixture = TestBed.createComponent(TestComponent);
comp = fixture.componentInstance;
});
}); // excess `)` removed
Now, onto the noteworthy error
A provider takes can take two forms.
The first is a value that acts as both the value provided and the key under which it is registered. This commonly takes the form of a class as in the following example
const Dependency = class {};
#NgModule({
providers: [Dependency]
}) export default class {}
The second is an object with a provide property specifying the key under which the provider is registered and one or more additional properties specifying the value being provided. A simple example is
const dependencyKey = 'some key';
const Dependency = class {};
#NgModule({
providers: [
{
provide: dependencyKey,
useClass: Dependency
}
]
}) export default class {}
From the above it you can infer that you failed to specify the actual value provided under the key TestingCompilerFactory.
To resolve this write
TestBed.configureTestingModule({
declarations: [TestComponent],
providers: [
{
provide: TestingCompilerFactory,
useClass: TestingCompilerFactory
}
]
})
which is redundant and can be replaced with
TestBed.configureTestingModule({
declarations: [TestComponent],
providers: [TestingCompilerFactory]
})
as described above.
Notes
In the future do not post questions that include such an obvious error - fix it yourself instead.
Do not post two questions as one.
I'm new to Angular5 and TypeScript, so it's very possible it's a simple thing I'm overlooking.
I have an Angular hybrid app that uses ngUpgrade to run AngularJS and Angular5 side-by-side. I'm trying to inject $templateCache into the OnAppInit function so that I can load all the AngularJS HTML templates before the app completely initializes. I'm getting the error "Cannot find name '$templateCacheService'" as indicated below. Is my syntax wrong or is this not possible?
I "upgrade" $templateCache in upgraded-providers.ts like this:
import { InjectionToken, Directive, ElementRef, Injector } from '#angular/core';
import { UpgradeComponent } from '#angular/upgrade/static';
export const $templateCacheService = new InjectionToken<any>('$templateCacheService');
export const $templateCacheServiceProvider = {
provide: $templateCacheService,
useFactory: (i: any) => i.get('$templateCache'),
deps: ['$injector']
};
Then in app.module.ts, I try to inject it into OnAppInit:
import { NgModule, APP_INITIALIZER, Inject } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { BrowserAnimationsModule } from '#angular/platform-browser/animations';
import { MatCommonModule } from '#angular/material';
import { FlexLayoutModule } from '#angular/flex-layout';
import { HttpClientModule, HttpClient, HTTP_INTERCEPTORS } from '#angular/common/http';
import { downgradeInjectable, UpgradeModule, downgradeComponent } from '#angular/upgrade/static';
import { environment } from '../environments/environment';
import {
$templateCacheServiceProvider,
$templateCacheService
} from './upgraded-providers';
import { AppComponent } from './app.component';
import { GlobalVarsService } from './core/global-vars.service';
import { WinAuthInterceptor } from './core/interceptors/win-auth.interceptor';
declare var angular: any;
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
BrowserAnimationsModule,
MatCommonModule,
FlexLayoutModule,
HttpClientModule,
UpgradeModule
],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: WinAuthInterceptor,
multi: true
},
{
provide: APP_INITIALIZER,
useFactory: OnAppInit,
multi: true,
deps: [GlobalVarsService, HttpClient, $templateCacheService]
},
GlobalVarsService,
$templateCacheServiceProvider
]
})
export class AppModule {
constructor(private upgrade: UpgradeModule, private http: HttpClient) { }
ngDoBootstrap() {
angular.module('app').factory('globalVars', downgradeInjectable(GlobalVarsService));
this.upgrade.bootstrap(document.body, ['app'], { strictDi: true });
}
}
////// THIS NEXT LINE GETS error TS2304: Cannot find name '$templateCacheService' /////
export function OnAppInit(globalVars: GlobalVarsService, http: HttpClient, $templateCache: $templateCacheService) {
return (): Promise<any> => {
return new Promise((resolve, reject) => {
http.get(environment.apiBase + '/api/meta/data').subscribe(x => {
globalVars.MetaData = x;
globalVars.VersionNumber = globalVars.MetaData.versionNumber;
globalVars.IsDebugBuild = globalVars.MetaData.isDebugBuild;
globalVars.User = globalVars.MetaData.user;
globalVars.ApiBase = environment.apiBase;
globalVars.Templates.forEach(template => {
$templateCache.put(template.Item1, template.Item2);
});
resolve();
});
});
};
}
This is TypeScript type error, it doesn't affect how the application works (as long as compilation errors are ignored).
templateCacheService is not a valid type here, because $templateCacheService is a variable (injection token), not a type or an interface.
Only Angular class constructors are annotated with types for DI. Since factory functions are annotated with deps property, types in function signature exist only to provide type safety. If it's not needed, types can be skipped:
export function OnAppInit(
globalVars: GlobalVarsService, http: HttpClient,
$templateCache
) { ... }
Otherwise proper types should be used. $templateCache is an object with get, put, etc methods. Appropriate types are provided with AngularJS #types/angular type definitions. It will be something like:
export function OnAppInit(
globalVars: GlobalVarsService, http: HttpClient,
$templateCache: ng.ITemplateCacheService
) { ... }