[EDIT] I've created a demo repository with this error: https://github.com/SamanthaAdrichem/hybrid-lazy-load-angularjs-injector-error
We've followed the instructions, and all runs fine on normal hybrid, but adding lazy loading fails with the strange error above, and always implemented ui router the way the docs say (as you can see in the code below).
When loading the app all is fine, but when then clicking onto a lazy-loaded route we get the error
Transition Rejection($id: 0 type: 6, message: The transition errored, detail: Error: Trying to get the AngularJS injector before it being set.)
I've tried the solutions listed here
https://github.com/ui-router/angular-hybrid/issues/93
https://github.com/ui-router/angular-hybrid/issues/150
https://github.com/ui-router/angular-hybrid/issues/395
https://github.com/ui-router/sample-app-angular-hybrid/issues/10
But none of these solve it. We don't use ng serve because that crashes with random memory issues (probably also due to hybrid), and we need to proxy to a login page, but the login page and our project would be running on the same port, which isn't possible. So that needs some refactoring in the backend.
It does sometimes load a new chunk file depending on what page i'm going to. But mostly i get this error.
Funny part is, in the page i'm testing we're not using any hybrid code. Basically we're are no longer upgrading any code, we're only downgrading some observers to open modals of the older pages.
These are the versions we're running
"@angular/cli": "9.1.7",
"@angular/animations": "9.0.7",
"@angular/common": "9.0.7",
"@angular/compiler": "9.0.7",
"@angular/core": "9.0.7",
"@angular/forms": "9.0.7",
"@angular/localize": "9.0.7",
"@angular/platform-browser": "9.0.7",
"@angular/platform-browser-dynamic": "9.0.7",
"@angular/router": "9.0.7",
"@angular/upgrade": "9.0.7",
"@uirouter/angular": "6.0.1",
"@uirouter/angular-hybrid": "10.0.1",
"@uirouter/angularjs": "1.0.26",
"@uirouter/core": "6.0.5",
"@uirouter/rx": "0.6.5",
Below the detailed error and some code, don't know what else to share or what i can safely share.
Any suggestions on how to debug this would be lovely!
detailed error
stateService.ts?8765:537 Transition Rejection($id: 0 type: 6, message: The transition errored, detail: Error: Trying to get the AngularJS injector before it being set.)
$defaultErrorHandler @ stateService.ts?8765:537
eval @ stateService.ts?8765:379
processQueue @ angular.js?21b1:17963
eval @ angular.js?21b1:18037
$digest @ angular.js?21b1:19176
eval @ upgrade_module.ts?423f:268
schedulerFn @ event_emitter.ts?938d:96
SafeSubscriber.__tryOrUnsub @ Subscriber.ts?face:266
SafeSubscriber.next @ Subscriber.ts?face:208
Subscriber._next @ Subscriber.ts?face:140
Subscriber.next @ Subscriber.ts?face:100
Subject.next @ Subject.ts?4a10:71
EventEmitter.emit @ event_emitter.ts?938d:86
checkStable @ ng_zone.ts?9664:224
onHasTask @ ng_zone.ts?9664:314
ZoneDelegate.hasTask @ zone.js?d135:440
ZoneDelegate._updateTaskCount @ zone.js?d135:462
Zone._updateTaskCount @ zone.js?d135:284
Zone.runTask @ zone.js?d135:205
drainMicroTaskQueue @ zone.js?d135:601
Promise.then (async)
scheduleMicroTask @ zone.js?d135:584
ZoneDelegate.scheduleTask @ zone.js?d135:410
onScheduleTask @ zone.js?d135:294
ZoneDelegate.scheduleTask @ zone.js?d135:400
Zone.scheduleTask @ zone.js?d135:231
Zone.scheduleMicroTask @ zone.js?d135:251
scheduleResolveOrReject @ zone.js?d135:881
resolvePromise @ zone.js?d135:819
eval @ zone.js?d135:739
webpackJsonpCallback @ app.js?v=1591962370205:26
(anonymous) @ 0.js?v=1591962370205:1
stateService.ts?8765:538 Error: Trying to get the AngularJS injector before it being set.
at injectorFactory (angular1_providers.ts?397c:22)
at _callFactory (ng_module.ts?c185:163)
at _createProviderInstance (ng_module.ts?c185:74)
at resolveNgModuleDep (ng_module.ts?c185:74)
at _callFactory (ng_module.ts?c185:163)
at _createProviderInstance (ng_module.ts?c185:74)
at resolveNgModuleDep (ng_module.ts?c185:74)
at _callFactory (ng_module.ts?c185:163)
at _createProviderInstance (ng_module.ts?c185:74)
at resolveNgModuleDep (ng_module.ts?c185:74)
at NgModuleRef_.get (refs.ts?151c:134)
at applyNgModule (lazyLoadNgModule.ts?7cfb:143)
at applyModule (lazyLoadNgModule.ts?7cfb:79)
at ZoneDelegate.invoke (zone.js?d135:384)
at Object.onInvoke (ng_zone.ts?9664:224)
at ZoneDelegate.invoke (zone.js?d135:384)
at Zone.run (zone.js?d135:143)
at eval (zone.js?d135:891)
at ZoneDelegate.invokeTask (zone.js?d135:419)
at Object.onInvokeTask (ng_zone.ts?9664:224)
at ZoneDelegate.invokeTask (zone.js?d135:419)
at Zone.runTask (zone.js?d135:188)
at drainMicroTaskQueue (zone.js?d135:601)
Our main.ts
// Bootstrapping
import {enableProdMode, NgModuleRef, NgZone, ViewEncapsulation} from '@angular/core';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {dom, library} from '@fortawesome/fontawesome-svg-core';
import {UIRouter, UrlService} from '@uirouter/core';
import {icons} from 'app/scripts/modules/app-layout/icons/icons';
import 'bootstrap/dist/js/bootstrap.js';
import 'expose-loader?jQuery!expose-loader?$!jquery';
import 'expose-loader?moment!moment';
import 'scripts/app.module';
import 'scripts/homer';
import 'scripts/static.assets';
import {AppModule} from 'src/app/app.module';
import {environment} from 'src/environments/environment';
library.add(...icons);
dom.watch();
// If ready
if (/comp|inter|loaded/.test(document.readyState)) {
bootstrap();
} else {
document.addEventListener('DOMContentLoaded', bootstrap);
}
function bootstrap(): void {
if (true === environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(
AppModule,
[{
defaultEncapsulation: ViewEncapsulation.None
}]
).then((platformRef: NgModuleRef<AppModule>) => {
// Initialize the Angular Module
// get() the UIRouter instance from DI to initialize the router
const urlService: UrlService = platformRef.injector.get(UIRouter).urlService;
// Instruct UIRouter to listen to URL changes
platformRef.injector.get<NgZone>(NgZone).run(() => {
urlService.listen();
urlService.sync();
});
});
}
Our app.module.ts
import {HTTP_INTERCEPTORS, HttpClientModule} from '@angular/common/http';
import {DoBootstrap, NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {setAngularJSGlobal, UpgradeModule} from '@angular/upgrade/static';
import {MissingTranslationHandler, TranslateModule, TranslateService} from '@ngx-translate/core';
import {UIRouterUpgradeModule} from '@uirouter/angular-hybrid';
import * as angular from 'angular';
import {AngularModalObserver} from 'hybrid/modal/modal.observer';
import {AdvertiserLastTransactionsModalObserver} from 'hybrid/modals/advertiser-last-transactions-modal.observer';
import {CampaignsModalObserver} from 'hybrid/modals/campaigns-modal.observer';
import {GoogleModalObserver} from 'hybrid/modals/google-modal.observer';
import {InvoiceModalObserver} from 'hybrid/modals/invoice-modal.observer';
import {PublisherLastTransactionsModalObserver} from 'hybrid/modals/publisher-last-transactions-modal.observer';
import {TicketsModalObserver} from 'hybrid/modals/tickets-modal.observer';
import {AngularTranslationsObserver} from 'hybrid/translations/translations.observer';
import {DatepickerModule} from 'ngx-bootstrap/datepicker';
import {ModalModule} from 'ngx-bootstrap/modal';
import {PagesAdminModule} from 'pages/admin/admin.a2.module';
import {GdprCleanupModule} from 'pages/publisher/account/gdpr-cleanup/gdpr-cleanup.module';
import {LayoutEventsObserver} from 'scripts/modules/app-layout/layout-events.observer';
import {ElementsExternalLinkModule} from 'scripts/modules/elements/external-link.a2/external-link.module';
import {ElementsPageHeaderModule} from 'scripts/modules/elements/page-header/page-header.module';
import {LocalizationMissingTranslationsService} from 'scripts/modules/localization/missing-translations.service';
import {AdminRoutingModule} from 'src/app/admin/admin-routing.module';
import {AdvertiserModule} from 'src/app/advertiser/advertiser.module';
import {AccountModel} from 'src/app/core/auth/account.model';
import {AuthObserver} from 'src/app/core/auth/auth.observer';
import {AuthService} from 'src/app/core/auth/auth.service';
import {IdentityService} from 'src/app/core/auth/identity.service';
import {TokenModel} from 'src/app/core/auth/token.model';
import {CoreModule} from 'src/app/core/core.module';
import {UserProfileModel} from 'src/app/core/data/backend/user/profile/user-profile.model';
import {AuthInterceptor} from 'src/app/core/interceptors/auth.interceptor';
import {CacheInterceptor} from 'src/app/core/interceptors/cache.interceptor';
import {GetAsPostInterceptor} from 'src/app/core/interceptors/get-as-post.interceptor';
import {GetMultiInterceptor} from 'src/app/core/interceptors/get-multi.interceptor';
import {LocalizationService} from 'src/app/core/localization/localization.service';
import {LeadgenerationModule} from 'src/app/leadgeneration/leadgeneration.module';
import {EnergyNlModule} from 'src/app/publisher/pages/widgets/widgets/energy/energy-nl/energy-nl.module';
import {PublisherModule} from 'src/app/publisher/publisher.module';
setAngularJSGlobal(angular);
@NgModule({
exports: [
TranslateModule
],
imports: [
AdminRoutingModule,
AdvertiserModule,
BrowserModule,
BrowserAnimationsModule,
CoreModule,
DatepickerModule.forRoot(),
ElementsExternalLinkModule,
ElementsPageHeaderModule,
GdprCleanupModule,
HttpClientModule,
LeadgenerationModule,
ModalModule.forRoot(),
PagesAdminModule,
PublisherModule,
TranslateModule.forRoot({
missingTranslationHandler: {
provide: MissingTranslationHandler,
useClass: LocalizationMissingTranslationsService
}
}),
UIRouterUpgradeModule.forRoot(),
UpgradeModule,
// These modules are needed here during hybrid
EnergyNlModule, // This one can be removed once the entire widget pages has been migrated
],
// All providers you need in AngularJS
providers: [
// These observers need to be here, it's required outside of it's own scope.
// Angular creates a new instance based on the require module level
AdvertiserLastTransactionsModalObserver,
AngularModalObserver,
AngularTranslationsObserver,
AuthObserver,
CampaignsModalObserver,
GoogleModalObserver,
InvoiceModalObserver,
LayoutEventsObserver,
PublisherLastTransactionsModalObserver,
TicketsModalObserver,
// Request interceptors, might be able to move them to the actual modules, but those are generated
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: CacheInterceptor, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: GetAsPostInterceptor, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: GetMultiInterceptor, multi: true },
]
})
export class AppModule implements DoBootstrap {
constructor(
private angularTranslationsObserver: AngularTranslationsObserver,
private identityService: IdentityService,
private authObserver: AuthObserver,
private authService: AuthService,
private localizationService: LocalizationService,
private translateService: TranslateService,
private upgrade: UpgradeModule
) {}
ngDoBootstrap(): void {
this.upgrade.bootstrap(document.body, ['dcApp'], { strictDi: true });
this.angularTranslationsObserver.languageChange$.subscribe(
(language: string) => this.localizationService.setLanguage(language)
);
this.angularTranslationsObserver.translationsChange$.subscribe(
(translations: object) => this.setTranslations(translations)
);
this.authObserver.accountChange$.subscribe(
(account: AccountModel) => this.identityService.setAccount(account)
);
this.authObserver.tokenChange$.subscribe(
(token: string) => {
this.authService.setToken(token);
let decryptedToken: TokenModel = this.authService.getDecryptedToken();
this.identityService.setAdmin(Boolean(decryptedToken && decryptedToken.admin));
this.identityService.setPermissions(decryptedToken.usg);
}
);
this.authObserver.userChange$.subscribe(
(user: UserProfileModel) => {
this.identityService.setUser(user);
this.localizationService.checkLanguageLocale();
}
);
}
setTranslations(translations: object): void {
for (const language in translations) {
if (translations.hasOwnProperty(language)) {
this.translateService.setTranslation(language, translations[language], true);
}
}
}
}
The admin-routing.module.ts
import {NgModule} from '@angular/core';
import {NgHybridStateDeclaration, UIRouterUpgradeModule} from '@uirouter/angular-hybrid';
const states: NgHybridStateDeclaration[] = [{
name: 'admin.**',
url: '/admin',
loadChildren: () => import('src/app/admin/admin.module')
.then((result: {AdminModule: any}) => result.AdminModule)
}];
@NgModule({
imports: [
UIRouterUpgradeModule.forChild({states: states})
],
exports: [
UIRouterUpgradeModule
],
})
export class AdminRoutingModule {}
And then the admin module
import {CommonModule} from '@angular/common';
import {NgModule} from '@angular/core';
import {MessageCenterModule} from 'src/app/admin/pages/message-center/message-center.module';
import {NewsModule} from 'src/app/admin/pages/news/news.module';
import {SearchModule} from 'src/app/admin/pages/search/search.module';
@NgModule({
declarations: [],
imports: [
CommonModule,
MessageCenterModule,
NewsModule,
SearchModule
]
})
export class AdminModule {}
and for example search.module
import {CommonModule} from '@angular/common';
import {NgModule} from '@angular/core';
import {TranslateModule} from '@ngx-translate/core';
import {ElementsMessagesModule} from 'scripts/modules/elements/messages.a2/messages.module';
import {ElementsNoResultsModule} from 'scripts/modules/elements/no-results.a2/no-results.module';
import {ElementsPageHeaderModule} from 'scripts/modules/elements/page-header/page-header.module';
import {BackendModule} from 'src/app/admin/data/backend/backend.module';
import {ItemModule} from 'src/app/admin/pages/search/item/item.module';
import {SearchRoutingModule} from 'src/app/admin/pages/search/search-routing.module';
import {SearchComponent} from 'src/app/admin/pages/search/search.component';
import {FilterModule} from 'src/app/core/components/filter/filter.module';
import {InputModule} from 'src/app/core/components/filter/input/input.module';
import {PanelModule} from 'src/app/core/components/panel/panel.module';
@NgModule({
declarations: [SearchComponent],
imports: [
BackendModule,
CommonModule,
ElementsMessagesModule,
ElementsNoResultsModule,
ElementsPageHeaderModule,
InputModule,
ItemModule,
PanelModule,
SearchRoutingModule,
TranslateModule,
FilterModule,
],
exports: [SearchComponent]
})
export class SearchModule { }
with search routing module as you can see not yet lazy loaded, when that will be introduced we would include search-routing module inside the admin module and refer to the search module in the routing module
import {NgModule} from '@angular/core';
import {UIRouterUpgradeModule} from '@uirouter/angular-hybrid';
import {StateDeclaration} from 'hybrid/state.declaration';
import {SearchComponent} from 'src/app/admin/pages/search/search.component';
import {BASIC} from 'src/app/core/auth/permissions/admin.constant';
const states: StateDeclaration[] = [{
name: 'admin.search',
url: '/admin/search',
component: SearchComponent,
permissions: [BASIC],
requiresAuth: true
}];
@NgModule({
imports: [
UIRouterUpgradeModule.forChild({states: states})
],
exports: [
UIRouterUpgradeModule
],
})
export class SearchRoutingModule {}
Our angularjs module
'use strict';
import angular from 'angular';
// Enable this line and the .run line to enable uiRouter visualizer
// import { visualizer } from '@uirouter/visualizer';
angular.module('dcApp', [
'dcApp.config', // this needs to be the very first dependency
'dcApp.publisher.campaigns.modal',
'dcLayout',
'dcLibRedirect',
'dcLibUniqueId',
/* Pages */
'dcApp.admin',
'dcApp.advertiser',
'dcApp.common',
'dcApp.leadgeneration',
'dcApp.publisher'
]);
// Enable this line and the import line to enable uiRouter visualizer
// angular.module('dcApp').run(['$uiRouter', ($uiRouter) => visualizer($uiRouter) ]);
/* Config files */
require('scripts/app-config/app-config.module');
require('scripts/helper/downloadfix');
require('scripts/helper/helper');
/* main module files */
require('scripts/app.controller');
require('hybrid/modal/modal.downgrade');
require('hybrid/cache-service.downgrade');
require('hybrid/modals/campaigns-modal.downgrade');
require('hybrid/modals/invoice-modal.downgrade');
require('hybrid/modals/tickets-modal.downgrade');
require('hybrid/modals/google-modal.downgrade');
require('hybrid/modals/advertiser-last-transactions-modal.downgrade');
require('hybrid/modals/publisher-last-transactions-modal.downgrade');
/* Other main modules */
require('pages/admin/admin.module');
require('pages/advertiser/advertiser.module');
require('pages/common.module');
require('pages/leadgeneration/leadgeneration.module');
require('pages/publisher/publisher.module');
```
and main app.controller
```
'use strict';
import angular from 'angular';
import $ from 'jquery';
require('scripts/modules/app-layout/layout.module');
angular.module('dcApp')
.controller( 'MainController', MainController );
MainController.$inject = [
'$location',
'$transitions',
'$window',
'AdvertiserFinancialInvoicesInvoiceDetailModal',
'AdvertiserLastTransactionsModalObserver',
'AdvertiserTransactionsOverviewDetailModal',
'AngularModalObserver',
'AppConfig',
'AppLayout',
'AuthAuthenticator',
'AuthAuthenticatorHelper',
'AuthIdentity',
'AuthObserver',
'CampaignInformationModal',
'ConnectionsGoogleLoginModal',
'ElementsMessagesHelper',
'GoogleModalObserver',
'InvoiceModalObserver',
'MediaVerificationModal',
'PublisherLastTransactionsModalObserver',
'TicketDetailModal',
'TicketsModalObserver',
'TransactionModal'
];
function MainController(
$location,
$transitions,
$window,
AdvertiserFinancialInvoicesInvoiceDetailModal,
AdvertiserLastTransactionsModalObserver,
AdvertiserTransactionsOverviewDetailModal,
AngularModalObserver,
AppConfig,
AppLayout,
AuthAuthenticator,
AuthAuthenticatorHelper,
AuthIdentity,
AuthObserver,
CampaignInformationModal,
ConnectionsGoogleLoginModal,
ElementsMessagesHelper,
GoogleModalObserver,
InvoiceModalObserver,
MediaVerificationModal,
PublisherLastTransactionsModalObserver,
TicketDetailModal,
TicketsModalObserver,
TransactionModal
) {
let $ctrl = this;
$ctrl.layout = AppLayout;
$ctrl.$onInit = onInit;
function onInit() {
initPage(true);
$transitions.onError( {}, function( transition ) {
let transitionError = transition.error();
if ([4,6].indexOf(transitionError.type) !== -1)
{
ElementsMessagesHelper.getInstance('generalError').addMessage( transition.error(), 'error', 'primaryError' );
AppLayout.hideSplashPage();
$location.path( '/error' );
}
} );
$transitions.onSuccess({}, function(transition) {
initPage(transition.from().name !== transition.to().name);
if ($window.ga) {
$window.ga('send', 'pageview', { page: $location.url() });
}
});
// No on destroy since the entire app is then gone
AuthObserver.loginAsChange$.subscribe(function __loginAs(loginAsModel) {
AuthAuthenticatorHelper.loginAs(
{
id: loginAsModel.account_id,
type: loginAsModel.account_type
},
loginAsModel.user_id || null,
loginAsModel.destination || null,
loginAsModel.sameWindow || null
);
});
AuthObserver.activityChange$.subscribe(AuthAuthenticator.updateLastActivity);
AuthObserver.logoutExpire$.subscribe(AuthAuthenticator.logoutExpire);
AuthObserver.updateAccount$.subscribe((account) => AuthIdentity.initAccount(AuthIdentity.getAccountType(), account));
AngularModalObserver.showMediaVerification$.subscribe((event) => MediaVerificationModal.show(event.mediaId));
InvoiceModalObserver.openModal$.subscribe(AdvertiserFinancialInvoicesInvoiceDetailModal.show);
PublisherLastTransactionsModalObserver.openModal$.subscribe((affiliatemarketingId) => TransactionModal.show(affiliatemarketingId));
AdvertiserLastTransactionsModalObserver.openModal$.subscribe((affiliatemarketingId) => AdvertiserTransactionsOverviewDetailModal.show(affiliatemarketingId));
TicketsModalObserver.openModal$.subscribe((ticketId) => TicketDetailModal.show(ticketId, false));
GoogleModalObserver.openModal$.subscribe(() => ConnectionsGoogleLoginModal.show())
}
function initPage(pageChange) {
if (pageChange) {
$(window).scrollTop(0);
}
$ctrl.currentPage = $location.path();
AppLayout.hideSplashPage();
}
}
You should be using UIRouterModule
from @uirouter/angular
instead of UIRouterUpgradeModule
from @uirouter/angular-hybrid
if you want to lazily load your angular module. Basically, avoid importing UIRouterUpgradeModule
and the mentioned error will go away -
SearchRoutingModule:
const states = [{
name: 'admin.search',
url: '/admin/search',
component: SearchComponent,
permissions: [],
requiresAuth: false
}];
@NgModule({
imports: [
UIRouterModule.forChild({states: states})
],
exports: [
UIRouterModule
],
})
export class SearchRoutingModule {}
AdminRoutingModule:
const states = [{
name: 'admin.search.**',
url: '/admin/search',
loadChildren: () => import ('./pages/search/search.module').then((module: any) => module.SearchModule)
}];
@NgModule({
imports: [
UIRouterModule.forChild({states: states})
],
exports: [
UIRouterModule
],
})
export class AdminRoutingModule {}
AppRoutingModule:
const adminStates = [{
name: 'admin.**',
url: '/admin',
loadChildren: () => import ('./admin/admin.module').then((module: any) => module.AdminModule)
}];
@NgModule({
imports: [
UIRouterModule.forRoot({states: adminStates})
],
exports: [
UIRouterModule
],
})
export class AppRoutingModule {}
Note:
There are some other errors that you'll get after above fix which should be easy to fix. Please post separate question for them if you're stuck.
After a long search and thanks to the help of two other users, the answer was actually really simple (as expected).
For some strange reason, we're exporting the UIRouterUpgradeModule which should've never been done. (We probably did this because we thought waaay back that thats how it worked? I don't know). But by removing the exports, the error goes away and everything works fine.
So for example that admin routing module becomes:
import {NgModule} from '@angular/core';
import {NgHybridStateDeclaration, UIRouterUpgradeModule} from '@uirouter/angular-hybrid';
const states: NgHybridStateDeclaration[] = [{
name: 'admin.**',
url: '/admin',
loadChildren: () => import('src/app/admin/admin.module')
.then((result: {AdminModule: any}) => result.AdminModule)
}];
@NgModule({
imports: [
UIRouterUpgradeModule.forChild({states: states})
]
})
export class AdminRoutingModule {}
Yes there are then some other errors, but those are easily solved. For example in my demo the AdminModule was still imported in the main module and should no longer be imported, since it's lazy loaded.
And each lazy ** state should also exist for example we made admin.**, that means that the AdminModule requires a route named admin. But that is literally said in the error.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With