I am trying to inject a controller into my app.run function, however i keep getting:
Uncaught Error: [$injector:unpr] http://errors.angularjs.org/1.2.10/$injector/unpr?p0=AuthenticationControllerProvider%20%3C-%20AuthenticationController
Here's my app.js:
var app = angular.module('app', [
'AuthenticationModule'
]);
app.run(['$rootScope', 'AuthenticationService', 'AuthenticationController',
function($rootScope, AuthenticationService, AuthenticationController) {
console.log(AuthenticationController);
}
]);
The AuthenticationService is injecting just fine. Why are AuthenticationController not being injected?
As stated in the AngularJS documentation on modules:
Run blocks - get executed after the injector is created and are used
to kickstart the application. Only instances and constants can be
injected into run blocks. This is to prevent further system
configuration during application run time.
In the documentation for controllers, it states:
In Angular, a Controller is a JavaScript constructor function that is
used to augment the Angular Scope. When a Controller is attached to
the DOM via the ng-controller directive, Angular will instantiate a
new Controller object, using the specified Controller's constructor
function.
A controller is an instance constructor function, not an instance itself, as opposed to a service, which is. Therefor, from what I can gather, controllers cannot be injected into a run block.
If you need to configure a controller at start-up time, then use a provider. As it turns out, in angular, controllers (along with directives, filters, and animations) are all simply syntactic sugar for a provider. Providers can be configured using configuration blocks: configuration block documentation
Configuration blocks - get executed during the provider registrations
and configuration phase. Only providers and constants can be injected
into configuration blocks. This is to prevent accidental instantiation
of services before they have been fully configured.
Related
I wonder how NgModule actually affects Angular 2 injector hierarchy.
What does the hierarchy look like in an app with nested modules? Does it create a new injector instance per each module or gets access to top-level injector (similarly to Angular 1.x modules)?
It can be somewhat confusing to figure out the tree in a big app.
Is there a way to print out, inspect or explore visually the hierarchy of injectors (like it could be done for scope hierarchy in Angular 1.x)?
According to the Modules documentation: https://angular.io/docs/ts/latest/guide/ngmodule.html
Angular registers these providers with the root injector of the module's execution context. That's the application's root injector for all modules loaded when the application starts.
Angular can inject one of these provider services into any component
in the application. If this module provides the HeroService, or any
module loaded at launch provides the HeroService, Angular can inject
the same HeroService intance into any app component.
A lazy loaded module has its own sub-root injector which typically is
a direct child of the application root injector.
Lazy loaded services are scoped to the lazy module's injector. If a
lazy loaded module also provides the HeroService, any component
created within that module's context (e.g., by router navigation) gets
the local instance of the service, not the instance in the root
application injector.
Components in external modules continue to receive the instance
created for the application root.
So, you have one injector that is shared between all the modules. However, lazy-loaded components will have a child injector
You should be able to investigate providers using ng.probe($0) in the browser console. See also https://stackoverflow.com/a/35233711/217408.
You can load modules with MyModule.forRoot() (see also https://angular.io/docs/ts/latest/guide/ngmodule.html#!#providers) to get providers added at the root level.
If you provide it in a module, then it's available to the components in this module. I haven't seen it mentioned that a module introduces a child injector explicitly but to me this looks like it has to be the case.
I'm working on a project that needs the backend to be mocked while the frontend implementation is being made.
I have a gulp structure that loads /**/*.mock.js files only for tests and while serving the source for development. I use this .mock.js files to mock test data and services and to intercept http calls for backendless development. The file looks like this:
(function() {
'use strict';
var mockResponseData = {
'mock': 'data'
};
angular
.module('module.name')
.value('mockResponseData', mockResponseData)
.config(config)
.run(run);
/** #ngInject */
function config($provide) {
$provide.decorator('$httpBackend', angular.mock.e2e.$httpBackendDecorator);
}
/** #ngInject */
function run($httpBackend) {
$httpBackend.whenPOST(/\/api\/path\/$/)
.respond(function() {
return [200, mockResponseData];
});
$httpBackend.whenGET(/^\w+.*/).passThrough();
$httpBackend.whenPOST(/^\w+.*/).passThrough();
$httpBackend.whenPUT(/^\w+.*/).passThrough();
$httpBackend.whenDELETE(/^\w+.*/).passThrough();
}
})();
As you can see, I already have the .passThrough() applied (which is the common solution for the Unexpected request issue) and it works just fine when just one .mock.js file like this exists. After creating the second file, the Unexpected request errors start to appear:
Error: Unexpected request: GET 'path/to/template.html'
After trying some things, I realized that the problem could be with the way I'm injecting $httpBackend. To avoid it from being injected in the dist files and to keep the project structure modular, I have to inject it via $provide instead of directly in the module's definition, in each module that needs it. Which is done in the config block of the code above.
If the $provide.decorator(...) line is removed from all but one .mock.js files, everything works fine again (except that the run block from the files with the line removed would start to complain about the non-existent $httpBackend, but this is not the issue here).
So, any idea of what this could be?
Thanks in advance!
P.S.: I can't miss the modularity structure and the .mock.js files cannot be included in the dist build.
So, I've solved this a while ago and now I'm answering here for future reference.
The basic problem is that I was injecting the $httpBackend service using the $provide.decorator() method, which according to the documentation, works like this:
Register a service decorator with the $injector. A service decorator intercepts the creation of a service, allowing it to override or modify the behavior of the service. The object returned by the decorator may be the original service, or a new service object which replaces or wraps and delegates to the original service.
Injecting the service like this was necessary to avoid injecting it when it wouldn't be used, but somehow, if you decorate this same service twice, AngularJS get confused and starts to throw the errors described in the question.
So, the solution is to create a .mock.js file for the main module. This way it will inject the service only once and avoid the problem:
(function() {
'use strict';
angular
.module('mainModuleName')
.config(config);
/** #ngInject */
function config($provide) {
$provide.decorator('$httpBackend', angular.mock.e2e.$httpBackendDecorator);
}
})();
Please note that you can still add more decorators to the service as follows:
$provide.decorator('$httpBackend', function($delegate, $injector) {
// Your decorator...
});
As long as you don't inject angular.mock.e2e.$httpBackendDecorator more than once.
In my previous question, I understand that the code var app = angular.module('myApp', []); connects the module app to the view myApp.
I would like to know why we are having the empty array [] in the module declaration.
What is the empty array used for?
angular.module('app', []) is to create a new module without any module dependency.
angular.module('app') is to retrieve an existing module whose name is app.
That array is meant to add various module to your current app which
is mentioned in your first part of angular.module as string`, You could simply
say for injecting various dependency.
You could create an n number of module inside your app for each component of angular & then you could combine them into one single app and you can angular.bootstrap or apply it on page using ng-app directive.
Example
Suppose you have an app which has different component like services, factory, filters, directives, etc. You could create a module for each of them. Just for making separation of concern.
angular.module('myApp.filters', [])
angular.module('myApp.services', [])
angular.module('myApp.controllers', [])
angular.module('myApp.directives', [])
angular.module('myApp.constants', [])
And while appending an component to it you could simply use that specific module of it. Like you wanted to add service then you just add that service into myApp.services by doing
angular.module('myApp.services').service('example', function(){
})
And then inside you app.js you could do combine all of this modules to an single module like below.
angular.module('myApp', [
'myApp.services',
'myApp.controllers',
'myApp.directives',
'myApp.directives',
'myApp.constants'
])
While initializing an app you could simply use myApp inside, that would make available all other module to it.
What is the empty array used for?
In you code you are creating an module which doesn't inject any dependency, [] which means it is independent of any other angular module.
Dependency injected inside the [] is nothing but importing module
Angulars API says Passing one argument retrieves an existing angular.Module, whereas passing more than one argument creates a new angular.Module
https://docs.angularjs.org/api/ng/function/angular.module
I am wondering how can I inject dependencies in more readable way in angular. I am more interested in AMD(requirejs) way. Like following:
define(function (require) {
var ModuleOne = require("ModuleOne"),
ModuleTwo = require("ModuleTwo");
var ThisModule = (function () {
// code here
})();
return ThisModule;
});
Is it possible to inject dependencies above way in angularjs or is there any better way to do it then current way in angularjs?
From the Angular JS official website
Angular modules solve the problem of removing global state from the
application and provide a way of configuring the injector. As opposed
to AMD or require.js modules, Angular modules don't try to solve the
problem of script load ordering or lazy script fetching. These goals
are orthogonal and both module systems can live side by side and
fulfil their goals.
Hence, purpose of both the libraries(RequireJS and AngularJS) is totally different. The dependency injection system built into AngularJS deals with the objects needed in a component; while dependency management in RequireJS deals with the modules or, JavaScript files.
In requireJS, Objects of loaded modules are cached and they are served when same modules are requested again. On the other hand, AngularJS maintains an injector with a list of names and corresponding objects. In this case, Object is served whenever it is referenced using the registered name.
Generally we inject dependencies in angularJS like
someModule.controller('MyController', function($scope,greeter){
});
If you want an alternative way to inject dependencies in angularJS, you may do something like.
var MyController = function($scope, greeter) {
// ...
}
MyController.$inject = ['$scope', 'greeter'];
someModule.controller('MyController', MyController);
Hope it helps!
MyApp.js:
'use strict';
angular.module('MyApp', [
'ngRoute',
'MyApp.components.hello',
'MyApp.pages.index',
'MyApp.pages.upload'
]).
config(['$routeProvider', 'HelloService', function($routeProvider, HelloService) {
$routeProvider.
when('/',
{
templateUrl: 'pages/index/index.html',
controller: 'IndexController'
}).
when('/upload',
{
templateUrl: 'pages/upload/upload.html',
controller: 'UploadController'
}).
otherwise({redirectTo: '/'});
HelloService.init({
facebook : ID_HERE
});
}]);
hello-service.js:
'use strict';
angular.module("MyApp.components.hello", []).
factory("HelloService", function()
{
return window.hello; //assume hello has been loaded
});
When I try to run it, I get the error Error: [$injector:unpr] Unknown provider: HelloService. Why? HelloService is clearly defined in MyApp.components.hello, which is included as a dependency of the main application. So why can't it find HelloService?
Check this article:
Understanding Dependency Injection by josepot
and this section
Configuring Providers
You may be wondering why anyone would bother to set up a full-fledged provider with the provide method if factory, value, etc. are so much easier. The answer is that providers allow a lot of configuration. We've already mentioned that when you create a service via the provider (or any of the shortcuts Angular gives you), you create a new provider that defines how that service is constructed. What I didn't mention is that these providers can be injected into config sections of your application so you can interact with them!
First, Angular runs your application in two-phases--the config and run phases. The config phase, as we've seen, is where you can set up any providers as necessary. This is also where directives, controllers, filters, and the like get set up. The run phase, as you might guess, is where Angular actually compiles your DOM and starts up your app.
So, where is the issue?
We can ask JUST for Providers to be injected into .config()
BUT - they are used in .config() just to be configured, not to be used
I don't think you can inject a service to config block.
Module Loading & Dependencies
Configuration blocks - get executed during the provider registrations
and configuration phase. Only providers and constants can be injected
into configuration blocks. This is to prevent accidental instantiation
of services before they have been fully configured.
Config is too early stage to star working with services, providers and factories.
Try moving that HelloService initialization part to run, like that:
.run(['HelloService', function(HelloService) {
HelloService.init({
facebook : ID_HERE
});
}])