I'm way overdue for injecting my first angular Factory . . .
My code:
.factory('Debts', function($q, $scope){
return MA;
})
.controller('Admin', function ($scope, Debts) {
$scope.Debts = Debts;
$scope.Debts.MA();
})
With $scope in my factory I get the following error:
Unknown provider: $scopeProvider <- $scope <- Debts
I read somewhere that we should not include $scope in the factory but when I take it out I get two errors:
1) Provider 'Debts' must return a value from $get factory method
2) Uncaught ReferenceError: $scope is not defined
The code for my factory is several hundred lines and yes it references $scope and $q. Please let me know what I need to change to make this work.
The $scope is available only for controllers and the link function of directives. This is why the factory cannot find it. Maybe you meant $rootScope?
.factory('Debts', function($q, $rootScope){
return MA;
})
???
Related
I am trying to test my AngularJs code.
My controller is shown here:
'use strict';
(function() {
angular.module('myApp')
.controller('TestController', function($scope, $http, Auth, myService, $state) {
try{
$scope.testVar = "Hello";
}catch(e){
console.log(e);
}
});
});
My test code is below:
'use strict';
describe('Controller: TestController', function () {
beforeEach(module('myApp'));
var TestController, scope;
beforeEach(inject(function ($controller, $rootScope) {
scope = $rootScope.$new();
TestController = $controller('TestController', {
$scope: scope
});
}));
it('should testVar to be defined', function () {
expect(scope).toBeDefined();
expect(scope.testVar).toBeDefined();
});
});
When I run it, it failed test with
Expected undefined to be defined
I don't know what I am doing wrong ...
I already checked many post on SO but didn't get it resolved yet.
Possibly issue is related to your variable declaration. You have declared ManualBookingController, but then you use TestController for the $controller line. Change ManualBookingController to TestController, see if that works.
I took your code almost as is, put it in a fiddle, test passes just fine. What I think might be missing in your case is you have some dependencies that are present in your controller but not mocked while creating the mock controller using $controller in your test suite. I removed them from your original controller (for now) and it worked fine.
And in order to mock $state (provider) and other services, you can see this same example fiddle passing with dependencies injected and read about underscore wrapping.
Also, keep in mind that sharing exact details on your question is very important. When I ran your test suite with your exact code, it first gave me following error:
Error: [$injector:unpr] Unknown provider: $stateProvider <- $state http://errors.angularjs.org/1.2.9/$injector/unpr?p0=%24stateProvider%20%3C-%20%24state
..which is not mentioned in your question at all. You mentioned only the next error Expected undefined to be defined which was very common and less-useful to imagine what's going on.
This question has been asked many times before and I've tried the answers but they do not seem to solve the problem I'm facing. I'm new to Angular and am trying to pass a value from the controller to a factory so that I can retrieve some JSON information through an API. While I'm able to get the value from my HTML to the controller, the next step is giving me a TypeError: Cannot read property 'getCityData' of undefined. My controller code is as follows:
app.controller('MainController', ['$scope', function($scope, HttpGetter) {
var successFunction = function(data) {
$scope.data = data;
}
var errorFunction = function(data) {
console.log("Something went wrong: " + data);
}
$scope.cityName = '';
$scope.getCityName = function(city) {
$scope.cityName = city;
HttpGetter.getCityData($scope.cityName, successFunction, errorFunction);
};
}]);
The factory code is as follows:
app.factory('HttpGetter', ['$http', function($http){
return {
getCityData: function(query, successFunction, errorFunction){
return $http.get('http://api.apixu.com/v1/current.json?key=MyAppKey&q=' + query).
success(successFunction).
error(errorFunction);
}
};
}]);
I've replaced my App key with the string "MyAppKey" just to be safe but my code contains the appropriate key. Also, it would be very helpful if I could get a bit of an insight on how the function invocations happen because there seem to be a lot of function callbacks happening.
Getting undefined could be because of the service not getting properly injected.
Try:
app.controller('MainController', ['$scope', 'HttpGetter', function($scope, HttpGetter)
Also as you said, to be on safer side you aren't using the right key, but anyone using your application can get the key by checking the network calls. So, ideally, one should make a call to the backend, and backend will send a call along with the secured key to the desired API endpoint and return the response data to front-end.
Can be due to ['$scope', function($scope, HttpGetter) ?
Should be ['$scope', 'HttpGetter', function($scope, HttpGetter) instead.
You used minified version and inject only $scope not HttpGetter but used as argument in controller function that's why got HttpGetter is undefiend and error shown Cannot read property 'getCityData' of undefined
So you should inject HttpGetter in your minified version ['$scope', 'HttpGetter'
use like:
app.controller('MainController', ['$scope', 'HttpGetter', function($scope, HttpGetter)
instead of
app.controller('MainController', ['$scope', function($scope, HttpGetter)
And if your MyAppKey is secured and want to hide from user then you should use it in server side
got error of scope not defined when i use for response message:
$scope.responsemessage = response;
then I added $scope here like this:
app.service('fileUpload', ['$http', '$scope', function ($http, $scope) {
When I added above $scope got this error Error: [$injector:unpr]
http://errors.angularjs.org/1.4.8/$injector/unpr?p0=.................
Service don't have scope.
If you wanna to use scope inside service , have to pass it from controller .
Like this
In controller
fileUpload.checkFile($scope.responsemessage);
In service
function checkFile(respMsg)
{
console.log(respMsg);
}
$scopes are not available from services, it should only be used inside controllers.
In angular $scope is available in controllers and services are used as a dependency for data provider.
You just can't use $scope in the service and from service you can return a promise object like:
app.service('fileUpload', ['$http', function($http) {
return $http.post('url')
}]);
Now you can inject this service to update a variable on the controller's $scope:
app.controller('cntrl', ['$scope', 'fileUpload', function($scope, fileUpload){
$scope.responsemessage = fileUpload.then(function(data){
return data;
})
}]);
You can not use $scope in Services as well as in Factories.
You can call service by giving $scope value as a parameter and save the return value to the $scope variable
I have this module as my main app which uses api:
var app = angular.module('app.main', ['api']);
app.controller('Home', function($scope, api, search){
$scope.search = function(){
api.search.lookup($scope.domain);
search.lookup($scope.domain);
};
});
I then have api which uses a few other modules like this:
var app = angular.module('api', [
'api.search'
// other modules here
]);
app.service('api', function($cookies, $http, $rootScope, search){
// Some more code
});
The search search module looks like this:
var app = angular.module('api.search', []);
app.service('search', function($scope, $http){
this.lookup = function(domain){
// query
};
});
When I run my controller and inject api, I can not access search because I get TypeError: Cannot read property 'lookup' of undefined, and if I inject search instead, I get this error:
Error: [$injector:unpr] http://errors.angularjs.org/1.4.3/$injector/unpr?p0=<div ng-view="" class="ng-scope" data-ng-animate="1">copeProvider%20%3C-%20%24scope%20%3C-%search
So, how can I access search from my controller?
The problem, as it seems, is that you are trying to inject $scope into a service generating function.
$scope is a local injectable available only for controllers, which makes sense, since scope is contextual to where the controller is defined and it has no meaning for singleton services.
Instead, you could inject $rootScope into a service, if needed.
app.service('search', function($rootScope, $http){
// ...
});
I have the following new service:
var SignatureService = function ($scope) {
this.announce = function () {
alert($scope.specificName);
}
};
SignatureService.$inject = ['$scope'];
This is declared for the app as follows:
MyAngularApp.service('SignatureService', SignatureService);
Several other services are added to the app in exactly the same way, and they all seem to work OK. I then have a controller declared and defined as follows:
MyAngularApp.controller('MyController', MyController);
...
var MyController = function ($scope, Service1, Service2, $location, $modal, SignatureService) {
...
}
MyController.$inject = ['$scope', 'Service1', 'Service2', '$location', '$modal', 'SignatureService'];
I am simply using the slightly unconvcentionaly manner of defining the servivce and injecting it that is standard in the app I am working on, as this works for all existing services, and I would prefer to simply slot mine in as per standard.
When the controller loads, I get an [$injector:unpr] in the browser console, with the error info:
$injector/unpr?p0=$scopeProvider <- $scope <- SignatureService
You can't inject $scope into your custom service. It just doesn't make sense since SignatureService can be injected anywhere including other services and other controlles. What $scope is supposed to be if you say inject it into two nested controllers, which one should be injected?
Scope object ($scope) is always associated with some DOM node, it is attached to it. That's why you see $scope in controllers and directives. And this is the reason why you can't have it in service: services are not related to specific DOM elements. Of course you can inject $rootScope but this is unlikely what you need in your question.
Summary: $scope is created from the $rootScope and injected in necessary controllers, but you can't injected it into custom service.
UPD. Based on comments you want to use service to define reusable controller methods. In this case I would go with what I call mixin approach. Define methods in the service and mix them in the necessary controllers.
app.service('controllerMixin', function() {
this.getName = function() {
alert(this.name);
};
});
and then extend controller scope with angular.extend:
app.controller('OneController', function($scope, controllerMixin) {
angular.extend($scope, controllerMixin);
// define controller specific methods
});
app.controller('TwoController', function($scope, controllerMixin) {
angular.extend($scope, controllerMixin);
// define controller specific methods
});
This is pretty effective, because controllerMixin doesn't have any notion of $scope whatsoever, when mixed into controller you refer to the scope with this. Also service doesn't change if you prefer to use controllerAs syntax, you would just extend this:
angular.extend(this, controllerMixin);
Demo: http://plnkr.co/edit/ePhSF8UttR4IgeUjLRSt?p=info