Nest can't resolve dependencies of the Service (?). Repository typeorm mysql problem - mysql

Any way to fix this? I am struggling with this for few hours now.
messages.service.ts (websocket service)
#Injectable()
export class MessagesService {
constructor(
private readonly messageService: MessageService,
private readonly userService: UserService,
) {}
... (Code that uses the DB methods from the services)
message.providers.ts
export const messageProviders = [
{
provide: 'MESSAGE_REPOSITORY',
useFactory: (dataSource: DataSource) => dataSource.getRepository(Message),
inject: ['DATA_SOURCE'],
},
];
room.providers.ts
export const roomProviders = [
{
provide: 'ROOM_REPOSITORY',
useFactory: (dataSource: DataSource) => dataSource.getRepository(Room),
inject: ['DATA_SOURCE'],
},
];
message.service.ts (db, typeorm mysql)
#Injectable()
export class MessageService {
constructor(
#Inject('MESSAGE_REPOSITORY')
private messageRepository: Repository<Message>,
) {}
async findAll(): Promise<Message[]> {
return this.messageRepository.find();
}
async findAllWithId(id: string): Promise<Message[]> {
return this.messageRepository.find({ where: { id } });
}
async createMessage(
name: string,
text: string,
roomId: string,
createdAt: string = new Date().toJSON().slice(0, 19).replace('T', ' '),
): Promise<Message> {
const newMessage = this.messageRepository.create({
name,
text,
roomId,
createdAt,
});
return this.messageRepository.save(newMessage);
}
}
room.service.ts (db, typeorm mysql)
#Injectable()
export class RoomService {
constructor(
#Inject('ROOM_REPOSITORY')
private roomRepository: Repository<Room>,
) {}
async findAll(): Promise<Room[]> {
return this.roomRepository.find();
}
async createRoom(
createdAt: string = new Date().toISOString().split('T')[0],
): Promise<Room> {
const newRoom = this.roomRepository.create({ createdAt });
return this.roomRepository.save(newRoom);
}
}
Messages.module.ts (websocket service)
import { MessagesService } from './messages.service';
import { MessagesGateway } from './messages.gateway';
import { Module } from '#nestjs/common';
import { MessageService } from 'src/db/services/message.service';
import { UserService } from 'src/db/services/user.service';
#Module({
imports: [MessageService, UserService],
providers: [MessagesGateway, MessagesService],
})
export class MessagesModule {}
ERROR
Nest can't resolve dependencies of the MessageService (?). Please make sure that the argument MESSAGE_REPOSITORY at index [0] is available in the MessageService context.
Potential solutions:
- If MESSAGE_REPOSITORY is a provider, is it part of the current MessageService?
- If MESSAGE_REPOSITORY is exported from a separate #Module, is that module imported within MessageService?
#Module({
imports: [ /* the Module containing MESSAGE_REPOSITORY */ ]
})

Related

how to resolve problem whem import repository in nestjs

im new in nestjs and i have one problem when i try to export my custom Repository, i dont any idea about how to resolve it.
gas-station.repository.ts i create custom repository:
#Injectable()
class GasStationRepository implements IGasStationRepository {
constructor(
#InjectRepository(GasStation)
private readonly gasStationRepository: Repository<GasStation>,
) {}
//...
public async createGasStation(
gasStationDto: ICreateGasStationDto,
): Promise<GasStation> {
const gasStation = this.gasStationRepository.create(gasStationDto);
await this.gasStationRepository.save(gasStation);
return gasStation;
}
public async bulkCreateGasStation(
gasStations: ICreateGasStationDto[],
): Promise<GasStation[]> {
return Promise.all(gasStations.map(this.createGasStation));
}
}
export default GasStationRepository;
gas-station.module.ts i thin it is normal formule to export my repository:
#Module({
imports: [TypeOrmModule.forFeature([GasStation])],
controllers: [GasStationController],
providers: [
GasStationService,
{
useClass: GasStationRepository,
provide: GAS_STATION_REPOSITORY,
},
],
exports: [
{
useClass: GasStationRepository,
provide: GAS_STATION_REPOSITORY,
},
],
})
export class GasStationModule {}
user.module.ts i import gasStationModule for use repository
#Module({
imports: [TypeOrmModule.forFeature([User]), GasStationModule],
controllers: [UserController],
providers: [
UserService,
{
useClass: UserRepository,
provide: USER_REPOSITORY,
},
],
})
export class UserModule {}
user.service.ts i will use repository :
#Injectable()
export class UserService {
constructor(
#Inject(USER_REPOSITORY) private readonly userRepository: IUserRepository,
#Inject(GAS_STATION_REPOSITORY)
private readonly gasStationRepository: IGasStationRepository,
) {}
async create(createUserDto: CreateUserDto) {
const {
type,
branches,
gasStations,
email,
password,
...props
} = createUserDto;
const existedUser = await this.userRepository.findByEmail(email);
if (existedUser) {
throw new BadRequestException('Usuário já cadastrado');
}
let gasStationList: ICreateGasStationDto[] = [];
let branchList: ICreateBranchDto[] = [];
if (type === 1 && gasStations && gasStations.length > 0) {
gasStationList = await this.gasStationRepository.bulkCreateGasStation(
gasStations,
);
} else if (type === 2 && branches && branches.length > 0) {
branchList = [];
}
const hashedPassword = await hash(password, 8);
const user = await this.userRepository.createUser({
type,
email,
password: hashedPassword,
...(branchList.length > 0 && { branches: branchList }),
...(gasStationList.length > 0 && { gasStations: gasStationList }),
...props,
active: false,
} as ICreateUserDto);
delete user.password;
return user;
}
//...
}
ERROR:
TypeError: Cannot read property 'gasStationRepository' of undefined
at createGasStation (/media/michelkuguio/Novo volume/easypetro/nest/epetro/dist/modules/gas-station/gas-station.repository.js:30:33)
at Array.map (<anonymous>)
at GasStationRepository.bulkCreateGasStation (/media/michelkuguio/Novo volume/easypetro/nest/epetro/dist/modules/gas-station/gas-station.repository.js:35:40)
at UserService.create (/media/michelkuguio/Novo volume/easypetro/nest/epetro/dist/modules/user/user.service.js:45:62)
at processTicksAndRejections (internal/process/task_queues.js:93:5)
at async /media/michelkuguio/Novo volume/easypetro/nest/epetro/node_modules/#nestjs/core/router/router-execution-context.js:46:28
at async /media/michelkuguio/Novo volume/easypetro/nest/epetro/node_modules/#nestjs/core/router/router-proxy.js:9:17
[Nest] 9228 - 19/04/2021 08:42:22 [HttpExceptionFilter] Http Status: 500 Error Message: {} +13880ms
The issue is in your bulkCreateGassStation method. gasStations.map(this.createGasStations) doesn't preserve the context where it is called from. You can either .bind(this) and set the context to be properly bound, or you can gasStations.map(station => this.createStations(station))

ERROR TypeError: Failed to execute 'setRequestHeader' on 'XMLHttpRequest': Value is not a valid ByteString

I create an application using Node.js and Angular9.
It is used to allow anyone to establish a company on the site. When an employee comes to create a
company, he presses on the site "create a company" and a form appears to put the company name,
address and domain for it, and when he presses the "create" button, this problem appears.
Knowing that the backend is NodeJs.
And when I create a company using Postman I don't have any problems.
The problem is only on the part of the Angular.
when I execute the code from the Angular side, I have this problem:
ERROR TypeError: Failed to execute 'setRequestHeader' on 'XMLHttpRequest': Value is not a valid ByteString
and this Error:
ERROR CONTEXT
This is the Code:
Company.server.ts:
import { Injectable } from '#angular/core';
#Injectable()
export class CompanyService {
constructor() { }
}
Company.server.spec.ts:
import { TestBed, inject } from '#angular/core/testing';
import { CompanyService } from './company.service';
describe('CompanyService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [CompanyService]
});
});
it('should be created', inject([CompanyService], (service: CompanyService) => {
expect(service).toBeTruthy();
}));
});
data.service.ts:
import { Injectable } from '#angular/core';
import { Observable } from 'rxjs';
import { HttpClient, HttpParams, HttpHeaders } from '#angular/common/http';
import { platformBrowserDynamicTesting } from '#angular/platform-browser-dynamic/testing';
import { BoundDirectivePropertyAst } from '#angular/compiler';
#Injectable()
export class DataService {
constructor(private httpClient: HttpClient) { }
create_company(body): Observable<any> {
var reqHeader = new HttpHeaders({
'Authorization': localStorage.getItem('token'),
'Content-Type': 'application/json'
});
return this.httpClient.post<any>
('http://localhost:3001/employee/company', body, { headers: reqHeader });
}
Company.component.ts:
import { Component, OnInit } from '#angular/core';
import { Router } from "#angular/router"
import { DataService } from '../../_services/data.service';
#Component({
selector: 'app-company',
templateUrl: './company.component.html',
styleUrls: ['./company.component.css']
})
export class CompanyComponent implements OnInit {
newCompany = {
company: {
name: '',
address: '',
domain: ''
}
}
public id: string;
public name: string;
public roles: any;
public email: string;
public token: string;
constructor(private dataService: DataService, private router: Router) { }
createCompany() {
console.log(JSON.stringify(this.newCompany));
console.log(localStorage.getItem('token'));
this.dataService.create_company(JSON.stringify(this.newCompany)).subscribe((data) => {
console.log(data);
})
}
logout() {
localStorage.clear();
this.router.navigate(['/register']);
}
ngOnInit() {
this.roles = localStorage.getItem('roles');
console.log(this.roles);
this.id = localStorage.getItem('id');
this.name = localStorage.getItem('name');
this.email = localStorage.getItem('email');
this.token = localStorage.getItem('token');
localStorage.setItem('id', "14ll06y4kbne6x6g");
localStorage.setItem('name', "Dalida");
localStorage.setItem('email', "dalida#gmail.com");
localStorage.setItem('roles', JSON.stringify([
{
roleId: 3,
targetId: '0',
employeeId: '14ll08o4kbm7apn9'
},
{
roleId: 2,
targetId: '4',
employeeId: '14ll08o4kbm7apn9'
}
]));
localStorage.setItem('token', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjE0b…
I2MH0.wHUoGDYqZIsty1DqUxUtkuQReBUidS4mC0MAQi1bMtQ');
}
}
How can I solve this problem?

NullInjectorError: No provider for JwtHelperService

I'm in Angular 5.
First: npm install #auth0/angular-jwt --save
Then I import it: import { JwtHelperService } from '#auth0/angular-jwt';
This is my authentication service:
import { JwtHelperService } from '#auth0/angular-jwt';
#Injectable()
export class AuthService {
constructor(public jwtHelper: JwtHelperService) { }
public isAuthenticated(): boolean {
console.log (localStorage['token']);
const token = localStorage.getItem('token');
// Check wheter the token is expired and return true or false
return !this.jwtHelper.isTokenExpired(token);
}
}
And this is my Guard service
export class GuardService implements CanActivate {
constructor(public auth: AuthService, public router: Router) {}
canActivate(): boolean {
if (!this.auth.isAuthenticated()){
console.log ('bye');
this.router.navigate(['/login']);
return false;
}
console.log ('Welcome');
return true;
}
}
There is a token in the localstorage:
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImFjMTUyNzZhZjA2MjU1YTdlMDM0MmQ5ODg4N2M1ZmI2ZWNmM2RlNGUyNjhmYTc4MTliODRhOTVmMmJiNGZiMTliMDFkNjBhNWRlNjhlN2VlIn0.eyJhdWQiOiJmMDExY2M1OC00MGNlLTQzYTktOGY3MS04NDI0OTRlM2E5OTciLCJqdGkiOiJhYzE1Mjc2YWYwNjI1NWE3ZTAzNDJkOTg4ODdjNWZiNmVjZjNkZTRlMjY4ZmE3ODE5Yjg0YTk1ZjJiYjRmYjE5YjAxZDYwYTVkZTY4ZTdlZSIsImlhdCI6MTUyMzI5NzkzNSwibmJmIjoxNTIzMjk3OTM1LCJleHAiOjE1MjMyOTgyMzUsInN1YiI6IjIiLCJzY29wZXMiOlsiYXV0aGVudGljYXRlZCIsImFuZ3VkcnUiXX0.RNY2Yb9xiJDcER4rtHEAYMmoLyvPYij-upZc97q-mSgICKE6_xWih_IBjY4cHQXkkiRyCXaqCfwfMM4YWVjv7bsMlLN5bWlH0JTeYoYf2gENLBIG51NwGpU3iAl8KG_51ljZKbs3RE_ULDbphM1NG8BhobVQ5RlObWzejrkPcMHqlGJaMOMLQuXC1iBR2jI9tlfiP4RD4FUUsRkUEUJ5PSIRl34jWoTv31SSf1bkv43q3YeKTfk6pXZ5Ft_eV8G871KkmQSHANAn26A5ujj2FOh-uCV_VNJ97RuTQ6J4NP2YB-mMaWYpZ1xF-4ndqafRGFXJ_8euBO4cA36zvP3B7g
And this is the error:
ERROR Error: Uncaught (in promise): Error: StaticInjectorError(AppModule)[AuthService -> JwtHelperService]:
StaticInjectorError(Platform: core)[AuthService -> JwtHelperService]:
NullInjectorError: No provider for JwtHelperService!
Error: StaticInjectorError(AppModule)[AuthService -> JwtHelperService]:
StaticInjectorError(Platform: core)[AuthService -> JwtHelperService]:
NullInjectorError: No provider for JwtHelperService!
at _NullInjector.get (core.js:1002)
at resolveToken (core.js:1300)
at tryResolveToken (core.js:1242)
at StaticInjector.get (core.js:1110)
at resolveToken (core.js:1300)
at tryResolveToken (core.js:1242)
at StaticInjector.get (core.js:1110)
at resolveNgModuleDep (core.js:10854)
at _createClass (core.js:10891)
at _createProviderInstance$1 (core.js:10865)
at _NullInjector.get (core.js:1002)
at resolveToken (core.js:1300)
at tryResolveToken (core.js:1242)
at StaticInjector.get (core.js:1110)
at resolveToken (core.js:1300)
at tryResolveToken (core.js:1242)
at StaticInjector.get (core.js:1110)
at resolveNgModuleDep (core.js:10854)
at _createClass (core.js:10891)
at _createProviderInstance$1 (core.js:10865)
at resolvePromise (zone.js:814)
at resolvePromise (zone.js:771)
at eval (zone.js:873)
at ZoneDelegate.invokeTask (zone.js:421)
at Object.onInvokeTask (core.js:4740)
at ZoneDelegate.invokeTask (zone.js:420)
at Zone.runTask (zone.js:188)
at drainMicroTaskQueue (zone.js:595)
Also, it shows me the route, but without the array from the service...
A little late to the party, but I ran into the same issue trying to follow the standalone docs and what it doesn't cover is the need to import the options InjectionToken which is referenced in the constructor of the service:
import { JwtHelperService, JWT_OPTIONS } from '#auth0/angular-jwt';
...
providers: [
{ provide: JWT_OPTIONS, useValue: JWT_OPTIONS },
JwtHelperService
]
You need to use JwtModule provided by the #auth0/angular-jwt, which will add JwtHelperService to the providers, or you need to add it manually to the modules provider.
Something like
const JWT_Module_Options: JwtModuleOptions = {
config: {
tokenGetter: yourTokenGetter,
whitelistedDomains: yourWhitelistedDomains
}
};
#NgModule({
imports: [
JwtModule.forRoot(JWT_Module_Options)
],
...
Fore more see Documentation
This problem occurs because you have not added JWTmodule to imports in app.module.ts
export function tokenGetter() {
return localStorage.getItem("access_token");
}
JwtModule.forRoot({
config: {
tokenGetter: tokenGetter,
allowedDomains: ["example.com"],
disallowedRoutes: ["http://example.com/examplebadroute/"],
},
}),
For future reference, if all you want to use JwtHelper for is decoding, like in this case checking if the token is expired, then you can use this.
import { JwtHelperService } from '#auth0/angular-jwt';
const jwtHelper = new JwtHelperService();
#Injectable()
export class AuthService {
public isAuthenticated(): boolean {
const token = localStorage.getItem('token');
// Check if the token is expired and return true or false
return !this.jwtHelper.isTokenExpired(token);
}
Source: Documentation
I battled with this issue as well. I found a workaround:
Test configuration
In your modulename.spec.ts make sure that you configure a provider for the JwtHelperService (In my case it was AuthGuard.spec.ts):
import { TestBed, inject, waitForAsync } from '#angular/core/testing';
import { RouterTestingModule } from "#angular/router/testing";
import { HttpTestingController, HttpClientTestingModule } from '#angular/common/http/testing';
import { JwtModule, JwtHelperService } from '#auth0/angular-jwt';
import { AuthGuard } from './auth.guard';
let jwtHelper: JwtHelperService;
const testBedConfiguration = {
imports: [
RouterTestingModule.withRoutes([]),
HttpClientTestingModule,
JwtModule.forRoot({ // for JwtHelperService
config: {
tokenGetter: () => {
return '';
}
}
})
],
providers: [
AuthGuard,
JwtHelperService
]
}
describe('AuthGuard', () => {
beforeEach(() => {
TestBed.configureTestingModule(testBedConfiguration);
jwtHelper = TestBed.get(JwtHelperService);
});
it('should ...', inject([AuthGuard], (guard: AuthGuard) => {
expect(guard).toBeTruthy();
}));
});
This solved my issue, but since my implementation was in my auth service which is used by my authguard for the routes, I have to include that config in every single page I have protected by the authguard.
The simplest solution which worked for me is declaring constant variable type of "JwtHelperService" instead of declaring it in a constructor.
const helper = new JwtHelperService ();
Now use helper services with helper constant
return !helper.isTokenExpired(token);
If you used #auth0/angular-jwt to get the jwt assistance and used dependency injection to access the module it is necessary to import jwt module to the app.module.ts or what ever the module you used.moreover you have more privileges to configure your module importers with disallowed domains, allowed domains , header name, custom factory functions etc.
import { JwtModule } from "#auth0/angular-jwt";
import { HttpClientModule } from "#angular/common/http";
export function tokenGetter() {
return localStorage.getItem("access_token");
}
#NgModule({
bootstrap: [AppComponent],
imports: [
// ...
HttpClientModule,
JwtModule.forRoot({
config: {
tokenGetter: tokenGetter,
allowedDomains: ["localhost:3001", "foo.com", "bar.com"]
},
}),
],
})
export class AppModule {}
if you don't want to inject it, you can instantiate.
import { JwtHelperService } from "#auth0/angular-jwt";
const helper = new JwtHelperService();
const decodedToken = helper.decodeToken(myRawToken);
const expirationDate = helper.getTokenExpirationDate(myRawToken);
const isExpired = helper.isTokenExpired(myRawToken);
import { JwtModule, JwtHelperService } from '#auth0/angular-jwt';
public jwtHelper: JwtHelperService = new JwtHelperService();
constructor(
private http: Http,
) { }
decodeToken() {
const token = localStorage.getItem('token');
return this.jwtHelper.decodeToken(token);
}
this fixed my problem
https://github.com/auth0/angular2-jwt/issues/482#issuecomment-569251938
I fixed this issues by changing my import from :
import { JwtHelperService } from '#auth0/angular-jwt';
to
import { JwtHelperService } from '#auth0/angular-jwt/src/jwthelper.service';

Angular2 sync up between service and Component

I have a "HomeComponent", that displays the user name in the UI.
The user name is read from a json file using a service.
I have the service provided in the AppComponent (parent to HomeComponent) and reused in HomeComponent
AppComponent.html
<router-outlet></router-outlet>
AppComponent.ts
export class AppComponent {
constructor(private userService: UserService) {
this.userService.fetchUserDetails();
}
}
UserService.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { User } from '../models/user';
import 'rxjs/add/operator/first';
import 'rxjs/add/operator/toPromise';
#Injectable()
export class AppStateManagerService {
private userDetails: User;
private initializeUser(data) {
this.userDetails = new User();
this.userDetails.name = data.username;
this.userDetails.id = data.userid;
}
constructor(private http: HttpClient) {}
async fetchDeviceDetails() {
let response = await this.http
.get('./app/config/user.json')
.first()
.toPromise();
this.initializeUser(response);
return this.userDetails;
}
getUserDetails() {
return this.userDetails;
}
}
HomeComponent.html
<div>{{user && user.name}}</div>
HomeComponent.ts
export class HomeComponent {
user: User;
constructor(private userService: userService) {
this.user = this.userService.getUserDetails();
}
}
The problem I face here is, the HomeComponent gets initialized first, before the JSON parsing is complete, that is before fetchUserDetails() is complete in AppComponent, the getUserDetails() in HomeComponent is called and the user.name is null in the HTML, before being populated in the service.
Is there a way to sync this up? Without using Observable?
fetchDeviceDetails() is asynchronous so i hope you can agree with me that getUserDetails() will immediately return undefined. Simple stuff right?
So how to fix this: You need to let HomeComponent know that data is available. We do that using Observables. One example is:
fetchDeviceDetails(): Observable<any> {
return new Observable(observer => {
this.http.get(whatever).subscribe(
res => {
this.initializeUser(res);
observer.next(res);
}
);
});
}
Now you can subscribe to this event:
constructor(private userService: userService) {
this.userService.fetchDeviceDetails().subscribe(
res => this.user = res
);
}
Another option is to use a getter like this:
export class HomeComponent {
get user(): User {
return this.userService.getUserDetails();
}
constructor(private userService: userService) { }
}
This leverages Angular's change detection to ensure that the user data is set in the UI as soon as it is available.

setting google map API key from angular 2 service

Im using sebastine google map in angular 2 application. I know AgmCoreModule.forRoot({ apiKey: "xxxxxxxx" }) can be used to set API key but I need to set API key from a angular service in my #component is it possible....help needed.
You may need to update provide a custom provider like this { provide: MapsAPILoader, useClass: CustomLazyAPIKeyLoader } where you have imported AgmCoreModule.
And in CustomLazyAPIKeyLoader class override the load method.
import { Injectable, Inject } from '#angular/core';
import { Http, Response, Headers, RequestOptions } from '#angular/http';
import { MapsAPILoader, LAZY_MAPS_API_CONFIG, LazyMapsAPILoaderConfigLiteral, GoogleMapsScriptProtocol } from 'angular2-google-maps/core';
import { DocumentRef, WindowRef } from 'angular2-google-maps/core/utils/browser-globals';
#Injectable()
export class CustomLazyAPIKeyLoader extends MapsAPILoader {
private _scriptLoadingPromise: Promise<void>;
private _config: LazyMapsAPILoaderConfigLiteral;
private _windowRef: WindowRef;
private _documentRef: DocumentRef;
constructor( #Inject(LAZY_MAPS_API_CONFIG) config: any, w: WindowRef, d: DocumentRef, private http: Http) {
super();
this._config = config || {};
this._windowRef = w;
this._documentRef = d;
}
load(): Promise<void> {
if (this._scriptLoadingPromise) {
return this._scriptLoadingPromise;
}
const script = this._documentRef.getNativeDocument().createElement('script');
script.type = 'text/javascript';
script.async = true;
script.defer = true;
const callbackName: string = `angular2GoogleMapsLazyMapsAPILoader`;
this.http.get("getKey")
.subscribe((res: any) => {
this._config.apiKey = res._body;
script.src = this._getScriptSrc(callbackName);
this._documentRef.getNativeDocument().body.appendChild(script);
});
this._scriptLoadingPromise = new Promise<void>((resolve: Function, reject: Function) => {
(<any>this._windowRef.getNativeWindow())[callbackName] = () => { console.log("loaded"); resolve(); };
script.onerror = (error: Event) => { reject(error); };
});
return this._scriptLoadingPromise;
}
private _getScriptSrc(callbackName: string): string {
let protocolType: GoogleMapsScriptProtocol =
(this._config && this._config.protocol) || GoogleMapsScriptProtocol.HTTPS;
let protocol: string;
switch (protocolType) {
case GoogleMapsScriptProtocol.AUTO:
protocol = '';
break;
case GoogleMapsScriptProtocol.HTTP:
protocol = 'http:';
break;
case GoogleMapsScriptProtocol.HTTPS:
protocol = 'https:';
break;
}
const hostAndPath: string = this._config.hostAndPath || 'maps.googleapis.com/maps/api/js';
const queryParams: { [key: string]: string | Array<string> } = {
v: this._config.apiVersion || '3',
callback: callbackName,
key: this._config.apiKey,
client: this._config.clientId,
channel: this._config.channel,
libraries: this._config.libraries,
region: this._config.region,
language: this._config.language
};
const params: string =
Object.keys(queryParams)
.filter((k: string) => queryParams[k] != null)
.filter((k: string) => {
// remove empty arrays
return !Array.isArray(queryParams[k]) ||
(Array.isArray(queryParams[k]) && queryParams[k].length > 0);
})
.map((k: string) => {
// join arrays as comma seperated strings
let i = queryParams[k];
if (Array.isArray(i)) {
return { key: k, value: i.join(',') };
}
return { key: k, value: queryParams[k] };
})
.map((entry: { key: string, value: string }) => { return `${entry.key}=${entry.value}`; })
.join('&');
return `${protocol}//${hostAndPath}?${params}`;
}
}
this.http.get("getKey")
.subscribe((res: any) => {
this._config.apiKey = res._body;
script.src = this._getScriptSrc(callbackName);
this._documentRef.getNativeDocument().body.appendChild(script);
});
Above code will make it async.
I added an resolver to get the API key
import { Resolve, ActivatedRouteSnapshot } from '#angular/router'
import { Injectable, Inject } from '#angular/core'
import { SomeService } from '../services/some.service'
import { LazyMapsAPILoaderConfigLiteral, LAZY_MAPS_API_CONFIG } from '#agm/core'
import { Observable, of } from 'rxjs'
import { map, catchError } from 'rxjs/operators'
#Injectable()
export class GoogleMapAPiResolver implements Resolve<boolean> {
constructor(
private someService: SomeService,
#Inject(LAZY_MAPS_API_CONFIG)
private config: LazyMapsAPILoaderConfigLiteral
) {}
resolve(router: ActivatedRouteSnapshot): Observable<boolean> {
return this.someService.getGoogleMapApiKey().pipe(
catchError(error => {
return of(false)
}),
map(response => {
this.config.apiKey = response
return true
})
)
}
}
The SomeService consume an endpoint that return the Key
you have put the API key in the app.module.ts under the #NgModule
and make sure to enable Maps JavaScript API in the google cloud console
https://console.cloud.google.com/apis/library/maps-backend.googleapis.com
Thanks!
#NgModule({
imports: [
BrowserModule,
FormsModule,
AgmCoreModule.forRoot({
// please get your own API key here:
// https://developers.google.com/maps/documentation/javascript/get-api-key?hl=en
apiKey: 'API_KEY'
})
],
declarations: [ AppComponent, HelloComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }