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.
Related
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
Im working on a new Angular project with the following files:
//app.js
var mainApp = angular.module('mainApp', ['serviceA', 'serviceB', "ctrlA", 'ctrlB']);
//ctrlA.js
var ctlA = angular.module('serviceA', []);
ctlA.controller('menuController', ['$scope', 'serviceA', function($scope, serviceA) {
// ...
}]);
Is there a reason not to do it this way ?
//ctrlB.js
angular.module('mainApp')
.controller('ctrlB', ['$scope', 'serviceA', function($scope, serviceA) {
// ...
}]);
What Zenorbi, mentioned is absolutely right. However, thought of adding this information to conclude a better answer.
You can modularize the app into multiple segments to make it easy to understand. The segmentation can be
done in different ways.
Based on service types - this will be useful for small applications
var mainApp = angular.module('mainApp', [
'app.controllers', // Controllers
'app.directives', // Directives
'app.filters', // Filters
'app.services' // Services
]);
Example implementation of a module.
var ctrls = angular.module('app.controllers');
ctrls.controller('menuController', ['$scope', 'serviceA', function($scope, serviceA) {
// ...
}]);
According to the purpose of each module. For example, you can separate chart related classes to a separate module and isolate it from the main code base. This will allow parallel programming by someone else, as this module can act independent from the parent module.
Both implementations are valid, but the module system is there to make sure you separate a bigger application into modules. If serviceA, serviceB, ctrlA and ctrlB are closely related, you might as well bundle them into a module. If you want to have your services elsewhere, you may create a module called mainApp.services.
It is up to you, how you structure the code, but modules exist for a reason. To have more than one "thing" in them.
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 :-)
everywhere in application my company created we used this example of how to create a controller :
app.myFunnyController = function($scope.....){}
but i see that everywhere in test people are using this way of creating controllers:
app.controller('myFunnyController', function ($scope) {
}
And i can see that when i am creating my test and using app.myFunnyController declaration:
'use strict';
describe('publicCtrl', function(){
beforeEach(module('app'));
it("should be true", inject(function($controller){
var scope = {},
ctrl = $controller('myFunnyController', {$scope : scope});
expect(scope.data).toBe("test2");
}));
})
I getting an error of myFunnyController is not a function. If i using the second type of declaration, everything works fine. Why does this happend?
An other problem is that i am getting error: scope is not defined.
I am new to Karma and Unit testing for front end, what am i doing wrong?
From my understanding, the second syntax (app.controller(...)) registers the controller function on the module. The first syntax just adds the controller function as an attribute of the module. app.controller does a bit more magic under the hood so that when you call $controller('myFunnyController, ...) in your test, the module knows about the controller and can run it. This is the recommended way to define controllers according to the angular controllers guide.
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.