I try to inject a dependency into a controller. I have tried passing dependencies through an Array, through an inline anonymous function and to use controller.$inject. Nothing works and I'm ready to explode.
Most of the blogs and article that mention dependency injection shows a simple example, where the code passes the $scope and a dependency.... but when I try to replicate the code example nothing works.
There is something that I'm missing. Do I have to instantiate the dependency or how do I pass the dependency?
var myApp = angular.module('myApp', []);
function MyViewModel() {
this.theRightAnswer = 'The answer is 42';
}
myApp.controller('myController', ['$scope', 'MyViewModel', function ($scope, MyViewModel) {
$scope.theAnswer = MyViewModel.theRightAnswer;
}]);
Use either service/ Factory/ provider for that, & then through dependency Injection you can share the functionality in different controllers. Add following line in your code & it'll work as expected.
myApp.service('MyViewModel', MyViewModel);
http://plnkr.co/edit/7ZclGB93Soq5Ce8pFmkQ?p=preview
Related
I'm reasonably new to Angular, and I'm having a weird problem when trying to use Angular Bootstrap UI.
I already know that it's being injected correctly, as the Typeahead component is working fine. I'm just starting to switch old code that calls JQuery modals within the controller into bootstrap to make them more testable, but for some reason even though I inject $modal through to the controller, it remains undefined and I cannot use it.
var MYAPP = MYAPP || {};
(function (angular) {
var common = MYAPP.common,
controllers = common.controllers,
directives = common.directives,
factories = common.factories,
filters = common.filters,
services = common.services,
repositories = common.repositories,
application = angular.module('MyModule', ['ngAnimate','ui.bootstrap']);
application.directive('positiveInteger', directives.positiveInteger);
application.filter('decimalPrecision', filters.decimalPrecisionFilter);
application.service('httpService', ['$http', repositories.httpService]);
MYAPP.application = application;
})(window.angular);
Then the module (loading in a seperate js file) :
var MYAPP = MYAPP || {},
someModule = MYAPP.namespace('someModule');
(function (application) {
/****************** Controller definitions **********************/
application.controller('myController', ['$rootScope', '$scope', '$modal', someModule.myController]);
})(MYAPP.application);
Then here's the controller code :
var MYAPP = MYAPP || {},
someModule = MYAPP.namespace('someModule');
someModule.myController = function($rootScope, $scope, $modal) {
var _controller = this;
etc etc
And then myController would be called with the above arguments, including the injected $modal. $modal is undefined within the controller.
Weirdly I can see that ui.bootstrap is in there, as inspecting the loaded modules I can see it exists, as does the other components. For example, angular.modules('ui.bootstrap') returns ok. If I mis-spell it, or enter a dummy name - it complains as I'd expect.
Interestingly the same applies if I enter a 'bad' injection annotation against the controller. For example :
application.controller('myController', ['$rootScope', '$scope', '$modalXXXYYY', someModule.myController]);
returns :
[$injector:unpr] Unknown provider: $modalXXXYYYProvider <- $modalXXXYYY <- myController
I'm not sure what's going on here - or how to diagnose it. I've checked obvious things like if it's being loaded in twice, but nothing like that seems to be going on. It's quite a large application overall, so this is heavily simplified, but any input would be much appreciated.
Thanks in advance,
Tony
Ok I've figured it out - and now I feel stupid.
Basically I wasn't persisting the passed in value in any way, so whilst $modal was passed across to the controller, the point where I was debugging (within a controller method) no longer had the variable in scope - which gave me the (false) impression that it wasn't actually passing it at all.
It was just a case of persisting the value to the controller e.g. _controller.modalService = $modal, and that sorted it out.
Just to mention that, I am a very much newbie in Angularjs.
While writing a controller I see I can use
controller('MyController', ['$scope', function($scope) {}])
or
controller('MyController', function($scope) {})
What is the difference between the both ?
Both are same.
When the javascript code is minified, all local variables in the function are changed to smaller variables to reduce size. for example.
function (largevariablename){
largevariablename = 123;
}
will be converted to
function (a){
a= 123;
}
But in case of angular if $scope is minified to s. Then the dependency injection fails searching for s. So angular injector will inject the the string value it finds in the array and inject it instead of the local varaiable in you define it in below way
controller('MyController', ['$scope', function($scope) {}])
So incase if your code in not going to be minified you can use the simple version
controller('MyController', function($scope) {})
This is mainly used for minification. When you minify the js
controller('MyController', function($scope) {})
will be converted to
controller('MyController', function(a) {})
and it will give the error for a is undefined. When you provide the dependency as
controller('MyController', ['$scope', function($scope) {}])
it will map a to $scope and it will work fine.
In fact, you should not use callbacks(Anonymous Functions) directly to define controllers.
You should use separate functions and $inject module to manually identify your dependencies.
controller('MyController', MyController);
MyController.$inject = ['$scope'];
function MyController($scope){
};
Why use named functions ?
This produces more readable code, is much easier to debug, and reduces
the amount of nested callback code.
Why use $inject ?
This technique mirrors the technique used by ng-annotate, which I
recommend for automating the creation of minification safe
dependencies. If ng-annotate detects injection has already been made,
it will not duplicate it.
Also, this safeguards your dependencies from being vulnerable to
minification issues when parameters may be mangled.
This is extracted from well-know John Papa Angularjs Style Guide
I'm kind of a big angularJS newbie and I'd like some highlights concerning dependency injection.
I've done some research and here is what I understand so far.
I have 2 service files (using factories) :
-mogService.js
angular.module('anglober.services').factory('mogService', ['$http', function($http) {
var mogService = {};
//mogService code here
return mogService;
}]);
-modalService.js
angular.module('anglober.services').factory('modalService', ['$modal',
function ($modal) {
//modalService code here
}]);
One controller file :
-mogCtrl.js
angular.module('anglober.controllers').controller('mogCtrl', ['$scope', 'mogService','modalService', function ($scope, mogService, modalService) {
//code using mogService and modalService parameters
}]);
As I understand it, the dependency injection is done by passing my services as parameters of the function parameter in my controller declaration, the array of string is here so that after minification, angular still knows which variable is what.
However, the modalService variable is undefined when I test my code. The mogService is recognized alright though (only if I remove any call to the modalService variable).
What am I doing wrong ?
I've read things about using $inject, which is the better practice and why ?
I'm declaring modules in the app.js as follows :
angular.module('anglober.services', ['ui.bootstrap']);
angular.module('anglober.controllers', []);
var app = angular.module('anglober', ['anglober.controllers', 'anglober.services', 'anglober.directives']);
Is this good practice ? Declaring modules and their respective dependencies in one file then only use "getters" without the dependencies array parameter in module files ?
Thanks for your time.
Three steps that work for me (plunkr):
1. Be sure you define a module's dependencies only once.
Indeed, check that angular.module('anglober.services', [...]); is indeed called only once with the second argument.
At the same time, be sure to call these lines before the actual services/controllers /... definitons.
2. Wire every dependency
You should add 'anglober.services' dependency to 'anglober.controllers': the last requires modalService which requires $modal, it may help angular anyway.
3. Add possible missing lib requirements, in the right order
First jQuery, then angular, bootstrap and eventually bootstrap.ui and your modules.
So this is really weird, maybe it has a simple answer I'm missing. The following code gives an unknown provider error:
var foo = angular.module('foo', [ 'ngRoute', 'ngAnimate', 'ngCookies' ]);
foo.factory('fooApi', function ($scope, $http) {
var url = '/api/';
var factory = {};
factory.action = function (fields) {
fields.userid = $scope.userid;
fields.token = $scope.token;
console.log(JSON.stringify(fields));
return $http.post(url, { data: fields });
};
return factory;
})
.controller('loginController', function ($scope, fooApi) {
// do stuff
});
It's all loading together in the same file, and I'd think the factory being first would resolve and the injector would be able to find it when referenced below. But it gives an unknown provider error.
However, if I comment out the controller and wait for the page to load and then do the exact same controller declaration in the Chrome JS console it works fine.
Anyone run into this before and know how to deal with it? I haven't been able to find this same exact issue anywhere.
Like #tasseKATT said, you can not inject $scope into a service, particularly a factory. Maybe your confusion is because $scope can be injected in controllers, so you tried to injected into a factory.
An interesting thing is that the $scope that you see being injected into controllers is not a service - like the rest of the injectable stuff -, but is a Scope object.
The main purpose of $scope is a king of glue between views and controllers, it doesn't make much sense to pass a $scope into a service.
The services only have access to the $rootScope service.
If you need to pass the $scope of a specific controller to a service always you can pass it like parameter of a function in the service. This approach is not recommended because starting to break the SoC and the single responsibility principle, but maybe could fit you.
Good luck :-)
Simple one I hope..
Here's a plunker for reference.
I know how to specify a dependency at compile-time (see MainCtrlInjected controller). But how do I pull down a dependency at runtime, giving the name of that dependency? (see MainCtrlInjectedRuntime controller)
You can use $injector to get your value at runtime:
Check my forked plunker: http://plnkr.co/edit/iVblEU?p=preview
Code:
app.controller('MainCtrlInjectedRuntime', [
'$scope',
'$injector'
($scope, $injector) ->
nameValHandle = 'nameVal'
# !!! This is how you inject at runtime
name = $injector.get(nameValHandle)
$scope.name = name
])
I am just getting into angularjs, but I believe the appropriate way to handle this situation would be to inject a service into MainCtrlInjectedRuntime. The injected service would have your somehowGetNameFromValue method.