i get the error "Unknown provider: {0}", if i try to call a service of the submodule inside the submodule
here the mainModule script
var mainApp = angular.module("mainApp", ["categoriesApp","ui.router"]);
//a service in the mainmodule which i can call with no problems in the submodule
mainApp.factory("getDataSvc", ["$http", "$q", "path", function ($http, $q, path) {
return{
...
some $http
....
}]);
and now the submodule
var categoriesApp = angular.module("categoriesApp", []);
//i can inject and use getDataSvc with no problems from the mainmodule
categoriesApp.controller("listCtrl", ["$scope", "getDataSvc", function ($scope, getDataSvc){
getDataSvc.categories().then(function(data){
...
})
}])
//my service in the submodule
categoriesApp.factory("sharedDataSvc", ["$scope", function ($scope){
return{
getValue: function(){
return "oioioioi";
}
}
}])
//in this line i get the error, if i try to inject the sharedDataSvc
//if i dont inject it, i get no errors, but cant use the service ;)
categoriesApp.controller("addBtnCrtl", ["$scope", "sharedDataSvc", function ($scope, sharedDataSvc){
console.log(sharedDataSvc.getValue());
}])
hope somebody can tell me what i`m doing wrong ;)
The problem is with sharedDataSvc factory
You cannot inject $scope to a factory because $scope is not a registered provider.
$scope is only injected to controllers ( within a locals object ).
categoriesApp.factory("sharedDataSvc", [ function (){
return{
getValue: function(){
return "oioioioi";
}
}
}])
each controller may be instantiated multiple time ( with each instance $scope is a different scope)
each service is instantiated only once and then cached ( the same instance injected everywhere)
Related
I'm trying to get a service working using AMD loading with require.js. I have my controllers all working and can load $rootScope to store app-wide variables/data but I would also like to add some methods to modify or refresh some of the app-wide data when needed. Thus I was trying to create a service object in require.js
So I create this sort of a thing:
MyService.js
define( ["angular"], function (angular) {
var MyService = function($scope, $rootScope) {
this.$scope = $scope;
this.$rootScope = $rootScope
}
MyService.$inject = ["$scope"];
MyService.prototype = {
constructor: MyService,
// comma separated list of methods and properties
}
return MyService
})
I similarly define a couple of controllers (all already working fine) then access them in my require.js config something like:
requirejs(
[ "angular", "MyService", "MyController" ],
function(angular, MyService, MyController) {
let myAppHandle = angular.module('myApp',[])
.service("myService", ['$scope','$rootScope', MyService])
// the following throws an error:
// angular.js:15697 Error: [$injector:unpr]
// Unknown provider: $scopeProvider <- $scope <- myService
myAppHandle.controller('MyController', ['$scope', 'myService', MyController])
}
)
Any help is appreciated
Ahh, I was guessing in the dark at how to create a service properly in require.js and after some tinkering and banging my face on the keyboard, I eventually figured out the problem was not with the controller getting the service, but with the service getting $scope
The examples I found for require.js dealt mostly with controllers, components and directives and and in just about every case, $scope was the first thing passed in.
I took $scope out of the .service() in the definition and in the constructor for the class and it's now working.
define( ["angular"], function (angular) {
var MyService = function($rootScope) {
// using $rootScope to store app-wide variables
// accessible directly or via this service
// potentially updated/populated by methods in this service
this.$rootScope = $rootScope
}
MyService.prototype = {
constructor: MyService,
// comma separated list of methods and properties
}
return MyService
})
and
requirejs(
[ "angular", "MyService", "MyController" ],
function(angular, MyService, MyController) {
let myAppHandle = angular.module('myApp',[])
.service("myService", ['$rootScope', MyService])
myAppHandle.controller('MyController', ['$scope', 'myService', MyController])
}
)
for reference, this is what the controller looks like:
define( ["angular"], function (angular) {
var MyController = function($scope, myService) {
this.$scope = $scope
// make service handle available as class property
this.myService = myService
}
MyController.$inject = ["$scope"];
MyController.prototype = {
constructor: MyController,
// comma separated list of methods and properties
}
return MyController
})
(Hopefully this will save someone else the 2-3 hours I took figuring this out)
app.config(['$controllerProvider','$compileProvider', '$filterProvider', '$provide',function($controllerProvider,
$compileProvider, $filterProvider, $provide) {
app.register = {
controller: $controllerProvider.register,
directive: $compileProvider.directive,
filter: $filterProvider.register,
factory: $provide.factory,
service: $provide.service
};
}
]);
app.controller('myCntrl', ['$scope', function($s) {
app.register.factory('customFactory',[customFactory]);
customFactory.init();
});
factory.js
function customFactory(){
var c= {};
c.init = function(){
console.log('init function');
}
return c;
}
Here I will be adding factory.js file in runtime and I now need to inject custom factory in my controller. So I have used $provide.factory method for it. But, I am not able to call init() function inside customFactory
Inside the controller that dynamically registers customFactory, the customFactory name binding is just a function. To call init() at the location you've noted, you'll need to invoke customFactory as a function.
customFactory().init();
However, if you've got another recipe elsewhere (e.g. controller) which needs to depend on customFactory, then you can access init() as you might expect.
app.controller('anotherCtrl', ['customFactory', function (customFactory) {
customFactory.init(); // OK!
}]);
When customFactory gets registered, the AngularJS dependency injector knows how to create it as a singleton and subsequently you can just access it as a value.
I created a service that has $interval as a dependency and makes use of it and seems to work. Unfortunately when I'm trying to unit test the app $interval service is not found by angular:
Unknown provider: $$qProvider <- $$q <- $interval
I am not calling the service inside a controller as usual, but on the run() method of the app:
app.service('myService', ['$rootScope', '$window', '$interval', myService]);
app.run(function (myService) {
...
});
It works, but if I try to test the app crashes. Rest of angular services don't seem to have this problem ($window, $location, $rootScope, ...) and even this same service works if I attach my service to a controller instead than calling it at app.run():
app.controller('myController', ['myService', function(myService){ ... }]);
I use Karma+Mocha+Sinon+Chai to test.
UPDATE
Example with mini app trying to use $interval at app.run():
var anApp = angular.module('myTestApp', ['ngRoute']);
anApp.run(function($rootScope, $timeout, $window, $location, $interval) {
// blah
});
The test:
describe("Lalarala", function() {
var scope = null;
beforeEach(function() {
module("myTestApp");
inject(function ($rootScope) {
scope = $rootScope.$new();
});
});
it("doesnt crash", function () {
//blah
});
});
Note: If you remove $interval from the app.run() it works. Instead, other angular services like $timeout, $window or $location don't seem to bother.
Also, I've noticed that other services like $resource have this problem too.
I presume some of those services require something else to be there before they are ready and that's why I can't call them at app.run()?
Thanks for any help.
This line is definitely wrong.
app.controller('myController', [myService, function(myService){ ... }]);
Array injection syntax should contain strings
app.controller('myController', ['myService', function(myService){ ... }]);
Ok,
After checking many things I found the problem had to do with an angular-mocks being out of date.
I updated versions of angular and angular-mocks and now everything is working fine.
Sorry!
I am creating a custom service which logs a user in to my system. In this service, I need to use core services such as $http - How do I actually depend these to be used in my service?
My current code:
.factory('loginService', ['$http', '$rootScope', function() {
var login = function(){
console.log($http);
}
return {login : login};
}])
I call the login function from a controller like so
loginService.login();
I hoped that my console will output the $http object I injected, but it's returning undefined.
How do I access this in the correct way?
You need to add the dependencies to your function arguments:
.factory('loginService', ['$http', '$rootScope', function($http, $rootScope) {
//You can use $http and $rootScope here now
}
See the official docs for more info on Dependency Injection in angular
Services you inject need to be passed as arguments of the function:
['$http', '$rootScope', function($http, $rootScope)
By the way, you'll need to do the same where you're trying to use it:
app.controller(['loginService', function (loginService) {
loginService.login();
});
try this:
var myapp = angular.module('mainApp', []);
myapp.controller('myController', ['$scope', 'myFactory', function($scope, myFactory) {
myFactory.login();
}]);
myapp.factory('myFactory', ['$http', function($http) {
var services = {};
services.login = function() {
console.log($http);
}
return services;
}]);
View:
<div ng-app='mainApp' ng-controller='myController'></div>
How can I emit events from a factory or service. I am unable to inject $scope into the factory, thus unable to emit events.
I get the following error - Unknown provider: $scopeProvider <- $scope
Thanks,
Murtaza
Inject $rootScope instead of $scope and then emit it on the $rootScope.
myApp.factory('myFactory', ['$rootScope', function ($rootScope) {
$rootScope.$emit("myEvent", myEventParams);
}]);
Factories don't have access to the current controller/directive scope because there isn't one. They do have access to the root of the application though and that's why $rootScope is available.
You cannot inject a controller's scope into a service. What you can do is:
pass the scope instance as a parameter to one of your service functions:
e.g.
app.factory('MyService', function() {
return {
myFunction: function(scope) {
scope.$emit(...);
...
}
};
});
inject the $rootScope into your service:
e.g.
app.factory('MyService', ['$rootScope', function($rootScope) {
return {
myFunction: function() {
$rootScope.$emit(...);
...
}
};
}]);
In your factory inject $rootScope as-
myApp.factory('myFactory',function($rootScope){
return({
// use $rootScope as below to pass myEventParams to all below in hierarchy
$rootScope.$broadcast("myEvent",myEventParams);
})
}]);