I have a piece of code(abc.ts file), which is responsible for loading a HTML related content using $routeProvider and angular.module.
Respective file is loading properly in local machine, but in server its resulting in a error as stated below.
Note: we are using AngularJs with TypeScript and JavaScript combination, also using Closure. Eventually JS & closure usage is being removed.
abc.ts file:
import 'angular-route';
import * as angular from 'angular';
import {AbcLinkController} from './filepath';
/** #ngInject */
function configureRoutes($routeProvider: angular.route.IRouteProvider) {
$routeProvider.when('abcLink/:pathVariable1:pathVariable2', {
templateUrl:'abclink/abc-file-name.ng',
controller: AbcLinkController,
controllerAs: 'ctrl'
});
}
export const module: angular.IModule =
angular.module('abc', ['ngMaterial', 'ngRoute'])
.config(configureRoutes);
Sinppet from app.js file:
module =
angular
.module(
'applicationName.app',
[
'ngMockE2E',
'ngRoute',
'ngSanitize',
'angularMoment',
abc.module.name,
...
Browser console error:
Error: [$injector:unpr] http://errors.angularjs.org/1.6.4-local+sha.617b36117/$injector/unpr?p0=%24%24routeParams%24%24Provider%20%3C-%20%24%24routeParams%24%24
at js.js?437e15ca-1865-4083-a6cd-f574d2d2b01d:4107
at js.js?437e15ca-1865-4083-a6cd-f574d2d2b01d:4142
at Object.y [as get] (js.js?437e15ca-1865-4083-a6cd-f574d2d2b01d:4139)
at js.js?437e15ca-1865-4083-a6cd-f574d2d2b01d:4142
at y (js.js?437e15ca-1865-4083-a6cd-f574d2d2b01d:4139)
at v (js.js?437e15ca-1865-4083-a6cd-f574d2d2b01d:4140)
at Object.instantiate (js.js?437e15ca-1865-4083-a6cd-f574d2d2b01d:4140)
at js.js?437e15ca-1865-4083-a6cd-f574d2d2b01d:4192
at Object.link (js.js?437e15ca-1865-4083-a6cd-f574d2d2b01d:4509)
at js.js?437e15ca-1865-4083-a6cd-f574d2d2b01d:4117 "<div ng-view=\"\" class=\"ng-scope\" data-ng-animate=\"1\">"
What could be wrong here?
Problem Summary
I am migrating an old AngularJS application to use Webpack and I am splitting it into three parts, which I want to represent as AngularJS modules:
src-ts-admin
src-ts-common
src-ts-store
For example I'd like 'src-ts-admin' to consume services from 'src-ts-common', but unfortunately webpack bundles files in the wrong order for AngularJS Dependency Injection, so that I end up with errors like ..
Error: "[$injector:unpr] Unknown provider: filterServiceProvider <- filterService <- initializerService
.. where initializerService is a service from src-ts-admin and filterService is from src-ts-common. The core of the problem is that
module("ADMIN").service("initializerService") executes before
module("COMMON).service("filterService")
.. although I cannot spot the problem in the dependencies.
File Overview
src-ts-admin: app.ts
This is the webpack entry point, however not so interesting. The application routing will trigger app.initializer.ts.
import angular from 'angular';
import { appModule } from './app.module';
src-ts-admin: app.module.ts
import angular from 'angular';
import commonModuleName from '../src-ts-common/common.module';
var modulezz;
modulezz = [commonModuleName,'ngRoute', 'ui.router', 'ui.multiselect', 'ui.bootstrap', 'ui.bootstrap-slider', 'ui.bootstrap.buttons', 'duScroll',
'ngMessages', 'colorpicker.module', 'angular-bind-html-compile', 'pascalprecht.translate'];
export var appModule = angular.module("ADMIN", modulezz);
export default appModule.name;
src-ts-admin: app.initializer.ts
import angular from "angular";
import appModuleName from "./app.module";
import { filterService } from "../src-ts-common/service/filter-service-model";
export class InitializerController {
static $inject = ...etc...
constructor(...etc...) {
/* THIS IS KICKED OFF BY AN ANGULAR ROUTE, THIS KICKS OFF THE InitializerController BELOW */
}
}
angular.module(appModuleName).controller("initializerController", InitializerController);
export class InitializerService {
static $inject = ["$stateParams", "$window", "$timeout", "filterService", ...etc...];
constructor(private $stateParams, private $window, private $timeout, private filterService: filterService, ...etc...) {
/* THIS IS WHERE THE DEPENDENCY INJECTION FAILS */
}
}
angular.module(appModuleName).service("initializerService", InitializerService);
src-ts-common: common.module.ts
import angular from 'angular';
export default angular.module("COMMON",[]).name;
src-ts-common: filter.service.ts
import angular from "angular";
import commonModuleName from '../common.module';
export class filterService {
static $inject = [];
constructor() {
/* ...simplified... */
}
}
angular.module(commonModuleName).service("filterService", filterService);
My thoughts
The error I get is ..
Error: "[$injector:unpr] Unknown provider: filterServiceProvider <- filterService <- initializerService
.. which indicates to me that app.initializer.ts is executed before filter.service.ts, although it is importing that file.
Do you see any obious errors I made? Do you have any best practices to structure AngularJS + Webpack module imports and cut files?
--- Solution (Update!) ---
Thanks to https://stackoverflow.com/a/59631154/5244937 I could solve my problem. The pattern I should have used was to initialize the angular modules (e.g. angular.module(commonModuleName).service("filterService", filterService);) in the app.module.ts and common.module.ts files and NOT together with their class implementations.
Here the corrected files:
src-ts-admin: app.ts
/* here i am more or less just kicking off the angular application after i import app.module.ts */
import { appModule } from './app.module';
appModule.run(["$rootScope", "$location", ...,
function ($rootScope, $location, ...) {
..
}
appModule.controller('appController', ['$scope', ..,
function ($scope: any, ...) {
..
}
src-ts-admin: app.module.ts
/** here (1) i am initializing all angular controllers, services, factories from the ADMIN package & (2) importing the COMMON module */
import angular from 'angular';
import ngRoute from 'angular-route';
import uiRouter from 'angular-ui-router';
import 'angular-messages';
import 'angular-translate';
import dptCommonModuleName from '../src-ts-common/common.module';
var modulezz;
modulezz = [dptCommonModuleName, ngRoute, uiRouter, 'ui.multiselect', 'ui.bootstrap', 'ui.bootstrap-slider', 'ui.bootstrap.buttons', 'duScroll',
'ngMessages', 'colorpicker.module', 'angular-bind-html-compile', 'pascalprecht.translate'];
export var appModule = angular.module("DPT", modulezz);
export var appModuleName = appModule.name;
/**
* Services
*/
angular.module(appModuleName).service("systemParameterService", systemParameterService);
angular.module(appModuleName).service("statisticsService", statisticsService);
angular.module(appModuleName).service("deletionCheckService", deletionCheckService);
...
src-ts-admin: app.initializer.ts
/** here i have removed (1) the import of angular.module.ts and (2) the initialization of angular controller and service "initializerController" and "initializationService" */
import angular from "angular";
import { filterService } from "../src-ts-common/service/filter-service-model";
export class InitializerController {
static $inject = ...etc...
constructor(...etc...) {
/* THIS IS KICKED OFF BY AN ANGULAR ROUTE, THIS KICKS OFF THE InitializerController BELOW */
}
}
export class InitializerService {
static $inject = ["$stateParams", "$window", "$timeout", "filterService", ...etc...];
constructor(private $stateParams, private $window, private $timeout, private filterService: filterService, ...etc...) {
/* THIS IS WHERE THE DEPENDENCY INJECTION FAILS */
}
}
src-ts-common: common.module.ts
/* here i have added the initialization of the angular service filterService and all other services, factories, .. contained in that module */
var moduleName = angular.module("DPT.COMMON",[]).name
export default moduleName;
angular.module(moduleName).factory("filterModel", function () { return filterModel; });
angular.module(moduleName).factory("filterPresetModel", function () {return filterPresetModel;});
angular.module(moduleName).factory("productModel", function () {return productModel;});
angular.module(moduleName).factory("propertyProfileModel", [function () {return propertyProfileModel;}]);
angular.module(moduleName).factory("propertyValueModel",function () {return propertyValueModel;});
src-ts-common: filter.service.ts
/** here i have (1) removed the import of common.module and (2) teh initialization of angular.module(..).service("filterService", ..) */
import angular from "angular";
export class filterService {
static $inject = [];
constructor() {
/* ...simplified... */
}
}
Your dependencies are inverted, Module should import its deps (other modules or filters / services / components).
If you will follow this, your AppModule will import its child modules, which in it turn will import its services.
That means that your services should only export the class.
The relevant Module should import the service class, and register it on the module & export the Module name.
The parent Module should import its child Modules.
// serviceX.js
export class serviceX {
static $inject=[];
...
}
// childModule.js
import {serviceX} from './services/serviceX.js';
import {componentY} from './components/componentY.js';
import angular from 'angular';
export default angular.module('childModule', [])
.service('serviceX', serviceX)
.component('componentY', componentY)
// ... rest of the childModule deps
.name;
// appModule.js
import {externalDep} from 'external-dep';
import childModule from './modules/childModule';
import angular from 'angular';
const appModule = anguler.module('appModule', [externalDep, childModule]).name;
angular.bootstrap(document, [appModule]);
I'm attempting an Angular app with a Grails backend, and I'm unit testing the controller, simply to see if it exist, before I start working with it. Unfortunately, it is giving me the following error:
[$controller:ctrlreg] The controller with the name 'SecurityController' is not registered.
Here's my unit testing code:
import angular from 'angular';
import 'angular-mocks';
import worldManagerApp from '../../src/world-manager-app';
import security from '../../src/security/security';
const {inject, module} = angular.mock;
describe('SecurityController', () => {
let $state;
let vm;
beforeEach(module(worldManagerApp));
beforeEach(module(security));
beforeEach(inject((_$state_, $controller) => {
$state = _$state_;
spyOn($state, 'go');
vm = $controller('SecurityController', {
});
}));
it('should be registered', () => {
expect(vm).toBeDefined();
});
});
Here is the controller code:
function SecurityController(){
'ngInject';
const vm = this;
vm.security = "secure";
}
export default SecurityController;
And here is the module code, for good measure:
import angular from 'angular';
import uiRouter from 'angular-ui-router';
import SecurityController from './securityController'
import SignUp from './services/signUpService';
import AuthenticationService from './services/authService'
const security = angular.module('security', [
uiRouter,
]).controller(SecurityController)
.service(SignUp)
.service(AuthenticationService);
export default security.name;
The security module is patched into my main app module, so I can provide that as well. I've read through a few resources regarding this, but nothing I've tried has been particularly helpful so far.
Thanks in advance!
.controller(SecurityController)
.service(SignUp)
.service(AuthenticationService);
should be
.controller('SecurityController', SecurityController)
.service('SignUp', SignUp)
.service('AuthenticationService', AuthenticationService);
You need to provide the name ov the controller/service, and then its implementation.
I'm trying to import a resource to a contoller with es6 imports.
I've got this resource:
import angular from 'angular';
import ngresource from 'angular-resource';
personsResource.$inject = ['$resource'];
function personsResource ($resource) {
// return $resource ...
}
export default angular.module('resources.persons', [ngresource])
.service('personsResource', personsResource)
.name
When in my module index.js I inject it like this:
//other imports
import personsResource from '../../resources/persons.resource';
//console.log(personsResource) returns resources.persons
export default angular.module('app.home', [personsResource])
.config(routing)
.controller('HomeController', HomeController)
.name
And my HomeController looks like this:
HomeController.$inject = [personsResource];
export default function HomeController(personsResource) {
}
And here personsResource is undefined. As I understand, I don't need to import it again in HomeController since I imported it in index.js and passed to HomeController from there.
I actually tried to import it again in HomeController but that didn't help either. Any ideas what I'm doing wrong?
Scenario
I'm trying to use a very simple angular 2 (rc.5) component as a directive inside my angular 1.5 app but I'm getting an error when adding the directive to one of my modules.
Error
[$injector:unpr] Unknown provider: ng2.ComponentFactoryRefMapProvider <- ng2.ComponentFactoryRefMap <- dummyDirective
Code
Angular2
jspm command for bundling: jspm bundle-sfx embeddedModule.ts dist/component-sfx.min.js --skip-source-maps --format global --global-name __myglobal
This component-sfx.min.js gets moved over into the proper location within the angular1 project
embeddedModule.ts
import 'rxjs/Rx';
import 'core-js/client/shim.js';
import 'zone.js';
import 'reflect-metadata/Reflect';
import { UpgradeAdapter, UpgradeAdapterRef } from '#angular/upgrade';
import { Component, provide, Inject, NgModule, forwardRef } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
const adapter = new UpgradeAdapter(forwardRef(() => EmbeddedModule));
#Component({
selector: 'dummy',
template: '<p>Hello!</p>'
})
class DummyComponent {
constructor() {
console.log('Dummy.constructor...');
}
}
#NgModule({
imports: [
BrowserModule
],
declarations: [
DummyComponent
]
})
class EmbeddedModule {}
var downgradedComponent = adapter.downgradeNg2Component( DummyComponent );
export { adapter, DummyComponent, downgradedComponent };
Angular 1 app
index.html
<script src=... angular vendor scripts ...></script>
<script src="path/to/my/angular2-sfx.js></script>
main.js
angular.element(document).ready(function() {
...
angular.bootstrap(document.body, ['my-app']);
...
});
my.controller.js (where I actually want to use my downgraded component)
(function() {
'use strict';
angular.module('data-gov-reference.state.index')
.controller('MyController', Index)
.directive('dummy', __myglobal.adapter.downgradeNg2Component(DummyComponent));
function Index() {
console.log('MyController...');
}
}());
myview/myview.html (the view where I want the downgraded directive to show up)
<div>
<dummy></dummy>
</div>
Nevermind, figured out the issue.
In main.ts, angular.bootstrap(...) should have been __myglobal.adapter.bootstrap(...)
main.ts
angular.element(document).ready(function() {
...
__myglobal.adapter.bootstrap(document.body, ['my-app']);
...
});
Hope it helps someone else!