Angular Universal: navigator is not defined - javascript

I followed official angular-cli tutorial to integrate angular-universal to my existing angular-cli app.
I am able to do SSR for my angular-cli app. But when I try to integrate ngx-leaflet, I am getting following error:
ReferenceError: navigator is not defined
at D:\ng2-ssr-pwa\dist\server.js:40251:29
Now, I understand that leaflet is trying to access navigator object which is not available in the Node context. So I decided to delay leaflet rendering until the page is loaded in the browser as given in this SO thread.
But still I am getting same error. You can look the demo app with leaflet issue here.
./src/app/browserModuleLoader.service.ts:
import { Component, Inject, Injectable, OnInit, PLATFORM_ID } from '#angular/core';
import { isPlatformBrowser, isPlatformServer } from '#angular/common';
#Injectable()
export class BrowserModuleLoaderService {
private _L: any;
public constructor(#Inject(PLATFORM_ID) private _platformId: Object) {
this._init();
}
public getL() {
return this._safeGet(() => this._L);
}
private _init() {
if (isPlatformBrowser(this._platformId)) {
this._requireLegacyResources();
}
}
private _requireLegacyResources() {
this._L = require('leaflet');
}
private _safeGet(getCallcack: () => any) {
if (isPlatformServer(this._platformId)) {
throw new Error('invalid access to legacy component on server');
}
return getCallcack();
}
}
./src/app/leaflet/app/leaflet.component.ts:
// import * as L from 'leaflet';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, PLATFORM_ID } from '#angular/core';
import { BrowserModuleLoaderService } from '../browserModuleLoader.service';
import { isPlatformBrowser } from '#angular/common';
#Component({
selector: 'app-leaflet',
styleUrls: ['./leaflet.component.scss'],
template: `
<div *ngIf="isBrowser">
<div leaflet [leafletOptions]="options"></div>
</div>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class LeafletComponent {
isBrowser: boolean;
options = {};
constructor(private cdr: ChangeDetectorRef,
#Inject(PLATFORM_ID) platformId: Object,
private browserModuleLoaderService: BrowserModuleLoaderService
) {
this.isBrowser = isPlatformBrowser(platformId);
}
ngAfterViewInit() {
console.log('this.isBrowser ', this.isBrowser);
if (this.isBrowser) {
const L = this.browserModuleLoaderService.getL();
this.options = {
layers: [
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 18, attribution: '...' }),
],
zoom: 5,
center: L.latLng({ lat: 38.991709, lng: -76.886109 }),
};
}
this.cdr.detach();
}
}
./src/app/app.component.html:
<div>
<app-leaflet></app-leaflet>
</div>
How do I safely delay the leaflet rendering until the platform is not browser?
EDIT:
I removed all code related to leaflet (browserModuleLoader.service.ts, leaflet.component.ts ect. ) and kept only leaflet module import in app.module.ts and actually this import is causing issue.
./src/app/app.module.ts:
import { AppComponent } from './app.component';
import { BrowserModule } from '#angular/platform-browser';
// import { BrowserModuleLoaderService } from './browserModuleLoader.service';
// import { LeafletComponent } from './leaflet/leaflet.component';
import { LeafletModule } from '#asymmetrik/ngx-leaflet';
import { NgModule } from '#angular/core';
#NgModule({
declarations: [
AppComponent,
// LeafletComponent
],
imports: [
BrowserModule.withServerTransition({appId: 'my-app'}),
LeafletModule.forRoot()
],
providers: [
// BrowserModuleLoaderService
],
bootstrap: [AppComponent]
})
export class AppModule { }
./src/app/app.server.module.ts:
import {AppComponent} from './app.component';
import {AppModule} from './app.module';
import {ModuleMapLoaderModule} from '#nguniversal/module-map-ngfactory-loader';
import {NgModule} from '#angular/core';
import {ServerModule} from '#angular/platform-server';
#NgModule({
imports: [
AppModule,
ServerModule,
ModuleMapLoaderModule
],
bootstrap: [AppComponent],
})
export class AppServerModule {}
How do I handle this nxg-leaflet module import?

Solved this issue by using Mock Browser.
server.ts:
const MockBrowser = require('mock-browser').mocks.MockBrowser;
const mock = new MockBrowser();
global['navigator'] = mock.getNavigator();

Fixed by (global as any).navigator = win.navigator;, much more elegant, definitely native, and without relying on outdated Mock Browser.

I too was receiving this error with Angular Universal. Using the Mock Browser from the solution above did fix this error for me, but it also started a new Warning related to CommonJS. Rather than digging into that issue, I realized I was already using Domino in my server.ts file, so I could easily set the navigator with Domino. This is what worked best for me:
npm install domino
server.ts:
const domino = require('domino');
const fs = require('fs');
const path = require('path');
const template = fs
.readFileSync(path.join('dist/<your-app-name>/browser', 'index.html')) //<--- REPLACE WITH YOUR APP NAME
.toString();
const window = domino.createWindow(template);
global['window'] = window;
global['document'] = window.document;
global['navigator'] = window.navigator;

Related

Nest.js cant resolve dependencies, can't find my mistake

I'm doing a Nest.js program but I can't find my dependencies problem. I have searched quite a lot and I have found a lot of answers regarding this problem, but I can't figure out why my code isn´t working. So I have a product module which has his DTO´s, Entity, Controller, Service and module, besides it has an interface for its service.
ProductController
import { Controller, Get } from '#nestjs/common';
import { ProductServiceInterface } from './interface/product.service.interface'
#Controller('products')
export class ProductController {
constructor(private readonly productService: ProductServiceInterface) {}
#Get()
getHello(): string {
return this.productService.test();
}
}
ProductServiceInterface
import { Injectable } from '#nestjs/common';
import {
CreateProductInput,
CreateProductOutput,
} from '../dto/create-product.dto';
import { FindProductOutput } from '../dto/find-product.dto';
export interface ProductServiceInterface {
create(input: CreateProductInput): Promise<CreateProductOutput>;
findProduct(productId: string): Promise<FindProductOutput>;
test();
}
ProductService
import { Injectable } from '#nestjs/common';
import { ProductServiceInterface } from './interface/product.service.interface';
import {
CreateProductInput,
CreateProductOutput,
} from './dto/create-product.dto';
import { Product } from './entity/product.entity';
import { InjectRepository } from '#nestjs/typeorm';
import { Repository } from 'typeorm';
import { FindProductOutput } from './dto/find-product.dto';
//import WooCommerce from '../../config/woocomerce.config';
#Injectable()
export class ProductService implements ProductServiceInterface {
constructor(
#InjectRepository(Product)
private productRepository: Repository<Product>,
) {}
public async create(
productDto: CreateProductInput,
): Promise<CreateProductOutput> {
const product = new Product();
product.name = productDto.name;
product.price = productDto.price;
product.imgUrl = productDto.imgUrl;
const savedProduct = await this.productRepository.save(product);
const productOutput = new CreateProductOutput();
productOutput.id = savedProduct.id;
return productOutput;
}
public async findProduct(idProduct: string): Promise<FindProductOutput> {
const fetchedProduct = await this.productRepository.findOne(idProduct);
const productOutput = new FindProductOutput();
productOutput.id = fetchedProduct.id;
productOutput.imgUrl = fetchedProduct.imgUrl;
productOutput.name = fetchedProduct.name;
productOutput.price = fetchedProduct.price;
return productOutput;
}
public test() {
return 'test'
// WooCommerce.get('products', {
// pero_page: 20,
// }).then((resp) => {
// return resp;
// });
}
}
ProductModule
import { ProductController } from './product.controller';
import { ProductService } from './product.service';
import { Product } from './entity/product.entity';
import { TypeOrmModule } from '#nestjs/typeorm';
import { Module } from '#nestjs/common';
#Module({
imports: [TypeOrmModule.forFeature([Product])],
controllers: [ProductController],
providers: [ProductService],
})
export class ProductModule {}
AppModule
import { Module } from '#nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ConfigModule } from '#nestjs/config';
import configuration from 'src/config/configuration';
import { TypeOrmModule } from '#nestjs/typeorm';
import { TypeOrmConfigService } from 'src/config/typeorm.config.service';
import { ProductModule } from './modules/product/product.module';
#Module({
imports: [
ConfigModule.forRoot({
load: [configuration],
isGlobal: true,
}),
TypeOrmModule.forRootAsync({
useClass: TypeOrmConfigService,
}),
ProductModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
I hope this code is enough for knowing where my mistake is, I don't like letting others just resolve this for me but I've been watching my code for hours and can't know how to resolve this dependencies problem.
Interfaces disappear at runtime and becomes {} or Object. Nest uses the parameter type metadata to determine what is supposed to be injected (usually via ClassType.name). You have two options to solve this
Use an abstract class instead of an interface. This makes the class still visible at runtime so ClassType.name still works.
Use #Inject('CustomToken') as the way to set the metadata for what Nest needs to inject. You then need to make sure register the custom provider using something like
{
provide: 'CustomToken',
useClass: ClassToBeUsed
}
Either of these methods should fix your issue.

How do I Access AppModule Module imports from Lazy-loaded Modules?

How do I Access AppModule imports from Lazy-loaded Modules ?
My Angular10 App imports AngularMaterial and NXTranslate Modules in to the AppModule.
NxTranslate calls an ApiService to get a large Lookup object of thousands of translations.
This is translated at the initial loading of the AppModule.
The App has multiple lazy-loaded routes that also need to use the AnagularMaterial and NXTranslate Modules in their features.
If I use a SharedModule to load the Modules then the ApiService is called multiple times. This is obviously not good.
It should only call the ApiService & AngularMaterial once and be available for all modules.
How do I resolve this? I am struggling.
Thanks.
Update
(sorry for the long post)
This is the NXTranslate implementation - it uses a custom class.
import { environment } from './../../../../environments/environment';
import { OSCITranslateService } from './translate.service';
import { NgModule, Injector } from '#angular/core';
import { CommonModule } from '#angular/common';
import {TranslateLoader, TranslateModule} from '#ngx-translate/core';
import {TranslateHttpLoader} from '#ngx-translate/http-loader';
import {HttpClient, HttpClientModule} from '#angular/common/http';
import { Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';
export class CustomLoader implements TranslateLoader {
localeResourcesUrl =
`${environment.baseUrl}${environment.apiUrl.localeResources}`;
constructor(private http: HttpClient) {}
getTranslation(lang: string): Observable<any> {
let options;
const uri = `${this.localeResourcesUrl}${options && options.key ?
'/' + options.key : ''}`;
let mapped = this.http.get(uri).pipe(
map((response: any) => {
let localeData = {};
let languageCode = response?.languageVariantCode;
response.resources.forEach(item => {
localeData[item.keyName] = item.keyValue;
});
return localeData;
})
);
return mapped;
}
}
#NgModule({
declarations: [],
imports: [
CommonModule,
HttpClientModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: CustomLoader,
deps: [HttpClient]
}
})
],
exports: [ TranslateModule ]
})
export class NxTranslateModule {
constructor(private http: HttpClient) {
}
}
This is the sharedRootModule that imports the AngularMaterial & NXTranslate
import { SharedModule } from './shared.module';
import { NgModule, ModuleWithProviders } from '#angular/core';
#NgModule({
})
export class SharedRootModule {
static forRoot(): ModuleWithProviders<SharedModule> {
return {
ngModule: SharedModule
};
}
}
In AppModule SharedRootModule is imported
...
#NgModule({
declarations: [
AppComponent
],
imports: [
...
SharedRootModule.forRoot()
],
exports: [
...
SharedRootModule
]
....
Are you concerned about the multiple ApiService instances you might end up with? Provide the ApiService within AppModule only, or even better, use the providedIn property right in your service's decorator so it gets injected at application level. (https://angular.io/api/core/Injectable#providedIn)
I would just use a SharedModule that exports the mentioned lazy loaded modules.

How to resolve ERROR NetworkError at XMLHttpRequest.send (...dist\fxcore\server\main.js:200768:19)

I am new to Angular. I just finished developing my angular web application. When I use ng serve to serve my application during production, everything works fine. I added angular universal. Now when I run any of npm run dev:ssr or npm run build:ssr && npm run serve:ssr, my application will refuse to open, throwing NetworkError response in the console. I noticed this error occurs for the number of times http requests where sent via class 'constructors(){..}'. I have browsed through several solution but couldn't get a clue of what I'm not doing right. My backend is developed with nodejs and express. I'll appreciate any help I can get.
Here is a full example of the error response I always get in the console.
ERROR NetworkError
at XMLHttpRequest.send (C:\Users\MRBEN\Desktop\Angular\fxcore\dist\fxcore\server\main.js:200768:19)
at Observable._subscribe (C:\Users\MRBEN\Desktop\Angular\fxcore\dist\fxcore\server\main.js:19025:17)
at Observable._trySubscribe (C:\Users\MRBEN\Desktop\Angular\fxcore\dist\fxcore\server\main.js:186304:25)
at Observable.subscribe (C:\Users\MRBEN\Desktop\Angular\fxcore\dist\fxcore\server\main.js:186290:22)
at scheduleTask (C:\Users\MRBEN\Desktop\Angular\fxcore\dist\fxcore\server\main.js:105897:32)
at Observable._subscribe (C:\Users\MRBEN\Desktop\Angular\fxcore\dist\fxcore\server\main.js:105959:13)
at Observable._trySubscribe (C:\Users\MRBEN\Desktop\Angular\fxcore\dist\fxcore\server\main.js:186304:25)
at Observable.subscribe (C:\Users\MRBEN\Desktop\Angular\fxcore\dist\fxcore\server\main.js:186290:22)
at subscribeToResult (C:\Users\MRBEN\Desktop\Angular\fxcore\dist\fxcore\server\main.js:196385:23)
at MergeMapSubscriber._innerSub (C:\Users\MRBEN\Desktop\Angular\fxcore\dist\fxcore\server\main.js:191575:116)```
I was still getting this ERROR NetworkError but I found another way to make this error go away. I think this answer is relevant since I was getting the same error posted above. If this can help anyone with that same server error then that's great.
If the api request is made to the server OnInit when reloading check isPlatformBrowser first when using ng-universal example.
import { Component, OnInit, PLATFORM_ID, Inject } from '#angular/core';
import { isPlatformBrowser } from '#angular/common';
import { HttpClient, HttpHeaders } from '#angular/common/http';
export class HomeComponent implements OnInit {
public testBrowser : boolean;
public data : any;
constructor(private http: HttpClient, #Inject(PLATFORM_ID) platformId: string) {
this.testBrowser = isPlatformBrowser(platformId);
}
ngOnInit() {
if (this.testBrowser) {
//avoid server NETWORK error
this.data = this.http.get('/api');
}
}
}
I was getting this same error trying to make server calls from the client before checking isPlatformBrowser === true first OnInit and this solved my problem. Hopefully this can help this bug.
For reference this answer helped me squash this long standing bug. https://stackoverflow.com/a/46893433/4684183
I am getting the same error. Try to remove TransferHttpCacheModule from your app.module and create your own custom http transfer interceptor file.
I made a file called transfer-state.interceptor.ts and then added it to app.module providers:[] to handle this. The examples below will show how I hooked it up. I am not sure if this will definitely work for you but it did make that error go away for me.
//app.module.ts
import { BrowserModule, BrowserTransferStateModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { HttpClientModule, HTTP_INTERCEPTORS } from "#angular/common/http";
//import {TransferHttpCacheModule } from '#nguniversal/common';
import { AppRoutingModule } from './app-routing/app-routing.module';
import { AppComponent } from './app.component';
import { HomeComponent } from './modules/home/home.component';
import { SliderComponent } from './components/slider/slider.component';
import { WindowRefService } from './services/window-ref.service';
//import { TransferHttpInterceptorService } from './services/transfer-http-interceptor.service';
import { TransferStateInterceptor } from './interceptors/transfer-state.interceptor';
import { ServiceWorkerModule } from '#angular/service-worker';
import { environment } from '../environments/environment';
#NgModule({
declarations: [
AppComponent,
HomeComponent,
SliderComponent
],
imports: [
BrowserModule.withServerTransition({ appId: 'serverApp' }),
BrowserTransferStateModule,
AppRoutingModule,
HttpClientModule,
ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production })
],
providers: [
WindowRefService,
{
provide: HTTP_INTERCEPTORS,
useClass: TransferStateInterceptor,
multi: true
}
],
bootstrap: [AppComponent]
})
export class AppModule { }
This is one version of a custom transfer state file but there are a few ways to do this if this one doesn't work.
//transfer-state.interceptor.ts
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '#angular/common/http';
import { Inject, Injectable, PLATFORM_ID } from '#angular/core';
import { Observable, of } from 'rxjs';
import { StateKey, TransferState, makeStateKey } from '#angular/platform-browser';
import { isPlatformBrowser, isPlatformServer } from '#angular/common';
import { tap } from 'rxjs/operators';
#Injectable()
export class TransferStateInterceptor implements HttpInterceptor {
constructor(
private transferState: TransferState,
#Inject(PLATFORM_ID) private platformId: any,
) {}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// For this demo application, we will only worry about State Transfer for get requests.
if (request.method !== 'GET') {
return next.handle(request);
}
// Use the request url as the key.
const stateKey: StateKey<string> = makeStateKey<string>(request.url);
// For any http requests made on the server, store the response in State Transfer.
if (isPlatformServer(this.platformId)) {
return next.handle(request).pipe(
tap((event: HttpResponse<any>) => {
this.transferState.set(stateKey, event.body);
})
);
}
// For any http requests made in the browser, first check State Transfer for a
// response corresponding to the request url.
if (isPlatformBrowser(this.platformId)) {
const transferStateResponse = this.transferState.get<any>(stateKey, null);
if (transferStateResponse) {
const response = new HttpResponse({ body: transferStateResponse, status: 200 });
// Remove the response from state transfer, so any future requests to
// the same url go to the network (this avoids us creating an
// implicit/unintentional caching mechanism).
this.transferState.remove(stateKey);
return of(response);
} else {
return next.handle(request);
}
}
}
}
If you want to add custom cache to this you can by installing memory-cache but I haven't tried that out yet. For more references these articles helped me out a lot and maybe they can help you too.
https://itnext.io/angular-universal-caching-transferstate-96eaaa386198
https://willtaylor.blog/angular-universal-for-angular-developers/
https://bcodes.io/blog/post/angular-universal-relative-to-absolute-http-interceptor
If you haven't you may need to add ServerTransferStateModule to your app.server.module file.
//app.server.module
import { NgModule } from '#angular/core';
import {
ServerModule,
ServerTransferStateModule
} from "#angular/platform-server";
import { AppModule } from './app.module';
import { AppComponent } from './app.component';
#NgModule({
imports: [
AppModule,
ServerModule,
ServerTransferStateModule
],
bootstrap: [AppComponent],
})
export class AppServerModule {}
good luck!
I was struggling with this error for days until I found this article About how to create a relative to absolute interceptor
here's the link
https://bcodes.io/blog/post/angular-universal-relative-to-absolute-http-interceptor
I created "universal-relative.interceptor.ts" file at my src folder
put this interceptor code in "universal-relative.interceptor.ts" file
import { HttpHandler, HttpInterceptor, HttpRequest } from '#angular/common/http';
import { Inject, Injectable, Optional } from '#angular/core';
import { REQUEST } from '#nguniversal/express-engine/tokens';
import { Request } from 'express';
// case insensitive check against config and value
const startsWithAny = (arr: string[] = []) => (value = '') => {
return arr.some(test => value.toLowerCase().startsWith(test.toLowerCase()));
};
// http, https, protocol relative
const isAbsoluteURL = startsWithAny(['http', '//']);
#Injectable()
export class UniversalRelativeInterceptor implements HttpInterceptor {
constructor(#Optional() #Inject(REQUEST) protected request: Request) {}
intercept(req: HttpRequest<any>, next: HttpHandler) {
if (this.request && !isAbsoluteURL(req.url)) {
const protocolHost = `${this.request.protocol}://${this.request.get(
'host'
)}`;
const pathSeparator = !req.url.startsWith('/') ? '/' : '';
const url = protocolHost + pathSeparator + req.url;
const serverRequest = req.clone({ url });
return next.handle(serverRequest);
} else {
return next.handle(req);
}
}
}
Go to your "app.server.module.ts" file
add your interceptor like this
import { NgModule } from '#angular/core';
import {
ServerModule,
ServerTransferStateModule,
} from "#angular/platform-server";
import { AppModule } from './app.module';
import { AppComponent } from './app.component';
import { UniversalRelativeInterceptor } from 'src/universal-relative.interceptor';
import { HTTP_INTERCEPTORS } from '#angular/common/http';
#NgModule({
imports: [AppModule, ServerModule, ServerTransferStateModule],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: UniversalRelativeInterceptor,
multi: true,
},
],
bootstrap: [AppComponent],
})
export class AppServerModule {}
And the error was GONE!
For me simply the error was that my API variable was undefined, because of the Angular SSR life-cycle. The data was only available after the browser module loaded.
I was using something like
this.isBrowser$.subscribe(isBrowser => { ... });
to set the appropriate api endpoint.
As David replied in the original issue, in my case was the resourceUrl variable that I was using, was not absolute for production environment.
environment.ts
export const environment = {
resourceUrl: 'http://localhost:8082/api/site',
siteId: '1111'
};
Like you see, for development, I was using an absolute url "http://localhost:8082/api/site" for resourceUrl environment variable. Ofcourse this was working on development mode.
environment.prod.ts
export const environment = {
resourceUrl: '/api/site',
siteId: '1111'
};
In production mode I was using a relative url (/api/site), and this was causing the issue while running "serve:ssr" which is production.
return this.http.get<ISomething>(`${environment.resourceUrl}/home/${environment.siteId}`);
So I changed environment.prod.ts to use an absolute URL. Then the issue was gone.
I am adding this reply, since maybe someone doesnt look at David comment. Thanks David.
In case someone needs, if you are using ng-universal, and because the server side rendering caused the error, then you can simply use
if (typeof window === 'object') {
// your client side httpClient code
}

use AngularJS service for Angular component

I have AngularJS service :
var id = 'authService';
angular.module('app')
.service(id, ['$http', '$q', '$injector', 'storageSvc', 'notifyHub', 'sysSettings', '$rootScope', 'crudSvc', authService]);
and would like to use it inside my angular component SignInComponent :
import { Component, Inject } from '#angular/core';
import { Account } from '../../../../shared/models/account';
import { AuthService } from "../../../../shared/angularJS-upgraded-providers";
#Component({
selector: 'sign-in',
templateUrl: './sign-in.component.html'
})
export class SignInComponent {
constructor(
#Inject(AuthService) private authService: any) {
this.authService = authService;
}
model = new Account('admin02', 'Admin#002', true);
onLogin() {
this.authService.login(this.model).then(response => {
if (response != null) {
alert("Seems it works");
}
});
}
}
For this purpose I created angularJS-upgraded-providers.ts file :
import { InjectionToken } from "#angular/core";
export const AuthService = new InjectionToken<any>('authService');
export function authServiceFactory(i: any) {
return i.get('authService');
}
export const authServiceProvider = {
provide: AuthService,
useFactory: authServiceFactory,
deps: ['$injector']
};
and trying to reuse it inside app.module.ts :
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { FormsModule } from '#angular/forms';
import { UpgradeModule } from '#angular/upgrade/static';
import { SignInComponent } from "./modules/login/components/sign-in/sign-in.component";
import { authServiceProvider } from './shared/angularJS-upgraded-providers';
#NgModule({
declarations: [
SignInComponent
],
imports: [
BrowserModule,
UpgradeModule,
FormsModule
],
entryComponents: [
SignInComponent
],
providers: [authServiceProvider
],
bootstrap: [SignInComponent]
})
export class AppModule {
constructor(private upgrade: UpgradeModule) { }
ngOnInit() {
this.upgrade.bootstrap(document.body, ['app']);
}
}
My start file - main.ts looks like this :
import { enableProdMode } from '#angular/core';
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule);
But when I am trying to run my program I have an error :
ERROR Error: Trying to get the AngularJS injector before it being set.
at injectorFactory (static.js:690)
at _callFactory (core.js:10956)
at _createProviderInstance$1 (core.js:10910)
at resolveNgModuleDep (core.js:10892)
at _callFactory (core.js:10958)
at _createProviderInstance$1 (core.js:10910)
at resolveNgModuleDep (core.js:10892)
at NgModuleRef_.push../node_modules/#angular/core/esm5/core.js.NgModuleRef_.get (core.js:12129)
at resolveDep (core.js:12619)
at createClass (core.js:12481)
Could please anybody provide algorithm or at least give an idea what i am doing wrong and why i am getting the error : Error: Trying to get the AngularJS injector before it being set?
Which template or pattern I could use to be able to consume AngularJS service inside my Angular5 app?
AngularJS version : 1.6.8,
Angular version : 5.2.11
Thank you for your time

Angular2 Loading the api configuration from the server side before the app bootstrap starts shows

I am using the angular 2 web app. In that, i am getting app configuration details from the api before the app bootsrap. For that i searched on the browser and find out these links
How to call an rest api while bootstrapping angular 2 app
https://gist.github.com/fernandohu/122e88c3bcd210bbe41c608c36306db9
And followed them. In the angular-cli and also on the browser console i didn't get any error. But my page comes empty with loading text, that was i displayed in the before loading angular.
Here is my code
app.module.ts
import { BrowserModule } from '#angular/platform-browser';
import { NgModule, APP_INITIALIZER } from '#angular/core';
import { FormsModule } from '#angular/forms';
import { HttpModule, Http} from '#angular/http';
import { SocketIoModule, SocketIoConfig } from 'ng2-socket-io';
import { SharedModule } from './shared/shared.module';
import { TranslateModule, TranslateLoader} from '#ngx-translate/core';
import { TranslateHttpLoader} from '#ngx-translate/http-loader';
import { AppRoutingModule } from './app.route';
import { AppComponent } from './app.component';
import { ChatComponent } from './chat/chat.component';
import { ChatService } from './chat/chat.service';
import { AddressComponent } from './address/address.component';
import { HomeComponent } from './home/home.component';
import { SettingService } from './shared/service/api/SettingService';
import { FilterByPipe } from './filterPipe';
import { Ng2ScrollableModule } from 'ng2-scrollable';
import { AppConfig } from './app.config';
import {Injectable} from '#angular/core';
import {Observable} from 'rxjs/Rx';
const config: SocketIoConfig = { url: 'http://192.168.1.113:7002', options: {} };
export function HttpLoaderFactory(http: Http) {
return new TranslateHttpLoader(http, "http://192.168.1.114:7001/frontend-translation/", "");
}
export function SettingServiceFactory(setting: SettingService) {
return () => setting.load();
//return true;
}
#NgModule({
declarations: [
AppComponent,
ChatComponent,
AddressComponent,
HomeComponent,
FilterByPipe
],
imports: [
BrowserModule,
FormsModule,
HttpModule,
AppRoutingModule,
Ng2ScrollableModule,
SocketIoModule.forRoot(config),
SharedModule,
TranslateModule.forRoot({
loader: {
provide : TranslateLoader,
useFactory: HttpLoaderFactory,
deps : [Http]
}
}),
],
providers: [
ChatService,
AppConfig,
SettingService,
{
provide : APP_INITIALIZER,
useFactory: SettingServiceFactory,
deps : [SettingService],
multi : true
}
/*SettingService,
{
provide : APP_INITIALIZER,
useFactory: (setting:SettingService) => () => setting.load(),
//deps : SettingService,
multi : true
}*/
],
bootstrap: [AppComponent]
})
export class AppModule { }
SettingService.ts
In this file, i am loading the api configuration from the server side
import {Injectable} from '#angular/core';
import {Http, Response} from '#angular/http';
import {Observable} from 'rxjs/Rx';
#Injectable()
export class SettingService {
public setting;
constructor(private http: Http) {}
/**
* Retrieves the setting details of the website
* #return {Object} language tranlsation
*/
public load()
{
return new Promise((resolve, reject) => {
this.http
.get('http://192.168.1.114:7001/settings')
.map( res => res.json() )
.catch((error: any):any => {
console.log('Configuration file "env.json" could not be read');
resolve(true);
return Observable.throw(error.json().error || 'Server error');
})
.subscribe( (envResponse) => {
this.setting = envResponse;
});
});
}
}
When i replace the load() api service within below code it works fine
public load() {
return {
"test": "works well"
}
}
But with api call, it doesn't.
What i found was, when i am returning the json object it works, but when i am making api call return the promise object it won't. I don't know how to solve this.
Thanks in advance.
My project was little bigger, so i can't put in plunker
Try to use promise object like this:
load(): Promise<Object> {
var promise = this.http.get('./app.json').map(res => res.json()).toPromise();
promise.then(res=> this.label= res);
return promise;
}

Categories