Jasmine + AngularJS: Global services causes Unexpected GET request - angularjs

I have a service, $language, that gets called in app config (so before every Spec runs). The method called, $language.update(), triggers $translate.use() (which in turn triggers an $http.get()). This causes an Unexpected request: GET /<lang>/i18n.
I've tried a few different things to resolve this, but each seems to cause a new problem:
Globally mock the $translate service
// not inside a describe()
beforeEach(function() {
module(function($provide) {
$provide.value('$translate', {
get: function() { return false; },
storage: function() { return false; },
storageKey: function() {
return {
get: function() { return false; },
set: function() { return false; }
};
},
use: function() { return false; }
});
});
});
But something tries to call $translate(), so I tried making the mock a function returning an object, but that didn't work either.
Mocking the GET request via $httpBackend
// not inside a describe()
beforeEach(function() {
// this already existed to avoid another problem caused by $translate
module('MyApp', function config($translateProvider, $anotherProvider) {
// …
});
// new
inject(function($httpBackend) {
$httpBackend.when('GET', '/<lang>/i18n').respond({});
});
});
But then it complains Injector already created, can not register a module! (order of module and inject doesn't seem to matter).
I thought of globally mocking my $language service, but then I would not be able to test it in its own Spec.
Ideally I'd prefer to globally mock $translate as it seems to cause one problem after another.

The problem was that $translate is a provider; therefore a provider needs to be $provide'd:
// Outside of a describe so it's treated as global
beforeEach(function() {
module('MyModule', function config($providerA, $provide) {
// …
$provide.provider('$translate', function() {
var store = {};
this.get = function() { return false; };
this.preferredLanguage = function() { return false; };
this.storage = function() { return false; };
this.translations = function() { return {}; };
this.$get = ['$q', function($q) {
var $translate = function(key) {
var deferred = $q.defer(); deferred.resolve(key); return deferred.promise;
};
$translate.addPair = function(key, val) { store[key] = val; };
$translate.isPostCompilingEnabled = function() { return false; };
$translate.preferredLanguage = function() { return false; };
$translate.storage = function() { return false; };
$translate.storageKey = function() { return true; };
$translate.use = function() { return false; };
return $translate;
}];
});
});
});

Related

Angular variable in factory?

In a Angular app i have a couple of calls to a WebAPI service.
The first call, lets call it call1, should determine a true/false value of a variable.
So i have this
vm.call1.$promise.then(function (data) {
$rootScope.variable1 = data.variable;
});
This variable is to be used inside a factory i have;
myApp.factory('myStore', function ($http, $q, $rootScope) {
var showAll = $rootScope.variable1;
var get = function () {
if (showAll) {
//do this
} else {
//do this
}
};
return {
get: get
};
});
My problem is, that the factory above is loaded on pageload, and before the promise, and therefore the value is undefined.
How can i get the value, over to my factory, after the promise is complete?
No rootscope example: You can set the showAll flag manually:
vm.call1.$promise.then(function (data) {
myStore.setShowAll(data.variable);
});
and in the Factory:
myApp.factory('myStore', function ($http, $q) {
var showAll = 'true or false to be a default';
var get = function () {
if (showAll) {
//do this
} else {
//do this
}
};
var setShowAll = function(value) {
showAll = value;
};
return {
get: get,
setShowAll: setShowAll
};
});
Rootscope example: If you for some reason really need to use $rootScope for this you can just check for $rootScope value when you get, you don't have to store the value in a varibale.
myApp.factory('myStore', function ($http, $q, $rootScope) {
var get = function () {
if ($rootScope.variable1) {
//do this
} else {
//do this
}
};
return {
get: get
};
});

Unit testing controller with injected service

What is the best way to go about unit testing the following controller? I'm having trouble properly injecting AuthService into my controller. I've seen so many different ways to do it and I'm not really sure what the best practice is - i.e. mocks vs spies?
I have a simple service like this:
angular.module('users')
.factory('AuthService', ['$http', '$window',
function($http, $window) {
var authService = {};
authService.login = function(creds) {
return $http.post('/auth', creds)
.then(function(res) {
$window.localStorage.exampleToken = res.data.returned_token;
return res;
});
};
authService.isLoggedIn = function() {
if($window.localStorage.exampleToken) {
return true;
} else {
return false;
}
};
authService.clear = function() {
delete $window.localStorage.exampleToken;
};
return authService;
}]);
My controller:
angular.module('users')
.controller('ExampleCtrl', ['AuthService',
function(AuthService) {
var vm = this;
vm.isLoggedIn = AuthService.isLoggedIn();
}]);
My unfinished test:
describe('ExampleCtrl', function() {
beforeEach(module('users'));
var ctrl;
beforeEach(inject(function($controller) {
ctrl = $controller('ExampleCtrl', {});
}));
describe('when logged in', function() {
beforeEach(function() {
// how do i mock the isLoggedIn function to
// return true
});
it('should return true', function() {
expect(ctrl.isLoggedIn).toBe(true);
});
});
describe('when not logged in', function() {
beforeEach(function() {
// how do i mock the isLoggedIn function to
// return false
});
it('should return false', function() {
expect(ctrl.isLoggedIn).toBe(false);
});
});
});
You can merely use the callFake function of Jasmine:
By chaining the spy with and.callFake, all calls to the spy will delegate to the supplied function.
var AuthService; //so that you can have a reference within all your test file
beforeEach(function() {
inject(function(_AuthService_) {
AuthService = _AuthService_;
});
spyOn(AuthService, 'isLoggedIn').and.callFake(function() {
return true;
});
});

Jasmine + AngularJS: Shared examples not loading

Jasmine keeps complaining that I have no tests in one of my shared specs, even though there are specs:
Spec 'mysite ProductsIndexCtrl behaves like an index controller' has no expectations.
my spec file looks like this:
//= require helpers/load-angular-ilook-module
//= require products/services/services
//= require products/controllers/products_index_controller
//= require helpers/shared_examples_for_products_index_controller
describe('mysite', function() {
var scope, ProductsIndexCtrl;
beforeEach(function() {
module('mysite');
});
describe('ProductsIndexCtrl', function() {
beforeEach(inject(function($controller, $rootScope, $injector) {
scope = $rootScope.$new();
$httpBackend = $injector.get('$httpBackend');
$httpBackend.when('/api/color_groups').respond([{"id":1,"name":"Browns","created_at":"2014-08-06T21:38:41.000Z","updated_at":"2014-08-06T21:38:41.000Z"},{"id":2,"name":"Blues","created_at":"2014-08-06T21:38:53.000Z","updated_at":"2014-08-06T21:38:53.000Z"},{"id":3,"name":"Greens","created_at":"2014-08-06T21:39:03.000Z","updated_at":"2014-08-06T21:39:03.000Z"}]);
$httpBackend.when('/api/shapes').respond([{"id":1,"name":"Round","created_at":"2014-05-23T17:10:32.000Z","updated_at":"2014-05-23T17:10:32.000Z"},{"id":2,"name":"Cat Eye","created_at":"2014-05-27T18:53:36.000Z","updated_at":"2014-05-27T18:53:36.000Z"},{"id":3,"name":"sharps","created_at":"2014-05-28T21:41:44.000Z","updated_at":"2014-07-02T14:13:59.000Z"},{"id":4,"name":"square","created_at":"2014-06-02T15:29:58.000Z","updated_at":"2014-06-02T15:29:58.000Z"},{"id":5,"name":"Round","created_at":"2014-06-02T15:35:06.000Z","updated_at":"2014-06-02T15:35:06.000Z"},{"id":6,"name":"fffff","created_at":"2014-07-02T14:14:23.000Z","updated_at":"2014-07-02T14:14:23.000Z"},{"id":7,"name":"Rectangular","created_at":"2014-07-29T15:17:01.000Z","updated_at":"2014-07-29T15:17:01.000Z"},{"id":8,"name":"Diamond","created_at":"2014-07-29T15:17:08.000Z","updated_at":"2014-07-29T15:17:08.000Z"}]);
$httpBackend.when('/api/materials').respond([{"id":1,"name":"Steel","created_at":"2014-05-23T17:04:42.000Z","updated_at":"2014-05-23T17:04:42.000Z"},{"id":2,"name":"Cotton","created_at":"2014-05-23T17:04:47.000Z","updated_at":"2014-05-23T17:04:47.000Z"},{"id":3,"name":"woods","created_at":"2014-05-28T20:26:16.000Z","updated_at":"2014-07-02T14:35:09.000Z"},{"id":4,"name":"plastic","created_at":"2014-06-02T15:30:05.000Z","updated_at":"2014-06-02T15:30:05.000Z"},{"id":5,"name":"glass","created_at":"2014-06-02T15:34:58.000Z","updated_at":"2014-06-02T15:34:58.000Z"},{"id":7,"name":"wood","created_at":"2014-06-02T16:51:47.000Z","updated_at":"2014-06-02T16:51:47.000Z"},{"id":8,"name":"rubber","created_at":"2014-07-02T14:35:51.000Z","updated_at":"2014-07-02T14:35:51.000Z"},{"id":9,"name":"carbon","created_at":"2014-07-29T14:52:44.000Z","updated_at":"2014-07-29T14:52:44.000Z"},{"id":10,"name":"paper","created_at":"2014-07-29T14:53:31.000Z","updated_at":"2014-07-29T14:53:31.000Z"},{"id":11,"name":"sandpaper","created_at":"2014-07-29T14:56:39.000Z","updated_at":"2014-07-29T14:56:39.000Z"},{"id":12,"name":"xfsdfsf","created_at":"2014-07-29T14:56:44.000Z","updated_at":"2014-07-29T14:56:44.000Z"}]);
ProductsIndexCtrl = $controller('ProductsIndexCtrl', {
'$scope': scope
});
$httpBackend.expectGET('/api/color_groups').respond([{"id":1,"name":"Browns","created_at":"2014-08-06T21:38:41.000Z","updated_at":"2014-08-06T21:38:41.000Z"},{"id":2,"name":"Blues","created_at":"2014-08-06T21:38:53.000Z","updated_at":"2014-08-06T21:38:53.000Z"},{"id":3,"name":"Greens","created_at":"2014-08-06T21:39:03.000Z","updated_at":"2014-08-06T21:39:03.000Z"}]);
$httpBackend.expectGET('/api/shapes').respond([{"id":1,"name":"Round","created_at":"2014-05-23T17:10:32.000Z","updated_at":"2014-05-23T17:10:32.000Z"},{"id":2,"name":"Cat Eye","created_at":"2014-05-27T18:53:36.000Z","updated_at":"2014-05-27T18:53:36.000Z"},{"id":3,"name":"sharps","created_at":"2014-05-28T21:41:44.000Z","updated_at":"2014-07-02T14:13:59.000Z"},{"id":4,"name":"square","created_at":"2014-06-02T15:29:58.000Z","updated_at":"2014-06-02T15:29:58.000Z"},{"id":5,"name":"Round","created_at":"2014-06-02T15:35:06.000Z","updated_at":"2014-06-02T15:35:06.000Z"},{"id":6,"name":"fffff","created_at":"2014-07-02T14:14:23.000Z","updated_at":"2014-07-02T14:14:23.000Z"},{"id":7,"name":"Rectangular","created_at":"2014-07-29T15:17:01.000Z","updated_at":"2014-07-29T15:17:01.000Z"},{"id":8,"name":"Diamond","created_at":"2014-07-29T15:17:08.000Z","updated_at":"2014-07-29T15:17:08.000Z"}]);
$httpBackend.expectGET('/api/materials').respond([{"id":1,"name":"Steel","created_at":"2014-05-23T17:04:42.000Z","updated_at":"2014-05-23T17:04:42.000Z"},{"id":2,"name":"Cotton","created_at":"2014-05-23T17:04:47.000Z","updated_at":"2014-05-23T17:04:47.000Z"},{"id":3,"name":"woods","created_at":"2014-05-28T20:26:16.000Z","updated_at":"2014-07-02T14:35:09.000Z"},{"id":4,"name":"plastic","created_at":"2014-06-02T15:30:05.000Z","updated_at":"2014-06-02T15:30:05.000Z"},{"id":5,"name":"glass","created_at":"2014-06-02T15:34:58.000Z","updated_at":"2014-06-02T15:34:58.000Z"},{"id":7,"name":"wood","created_at":"2014-06-02T16:51:47.000Z","updated_at":"2014-06-02T16:51:47.000Z"},{"id":8,"name":"rubber","created_at":"2014-07-02T14:35:51.000Z","updated_at":"2014-07-02T14:35:51.000Z"},{"id":9,"name":"carbon","created_at":"2014-07-29T14:52:44.000Z","updated_at":"2014-07-29T14:52:44.000Z"},{"id":10,"name":"paper","created_at":"2014-07-29T14:53:31.000Z","updated_at":"2014-07-29T14:53:31.000Z"},{"id":11,"name":"sandpaper","created_at":"2014-07-29T14:56:39.000Z","updated_at":"2014-07-29T14:56:39.000Z"},{"id":12,"name":"xfsdfsf","created_at":"2014-07-29T14:56:44.000Z","updated_at":"2014-07-29T14:56:44.000Z"}]);
$httpBackend.flush();
}));
//HERE!
it('behaves like an index controller', function() {
sharedExamplesForIndexControllers(scope);
});
});
});
That's weird because my shared_examples_for_products_index_controller.js file looks like this:
function sharedExamplesForIndexControllers(scope) {
it('sets color_groups', function() {
expect(JSON.stringify(scope.color_groups)).toEqual(JSON.stringify([{"id":1,"name":"Browns","created_at":"2014-08-06T21:38:41.000Z","updated_at":"2014-08-06T21:38:41.000Z"},{"id":2,"name":"Blues","created_at":"2014-08-06T21:38:53.000Z","updated_at":"2014-08-06T21:38:53.000Z"},{"id":3,"name":"Greens","created_at":"2014-08-06T21:39:03.000Z","updated_at":"2014-08-06T21:39:03.000Z"}]));
});
it('sets shapes', function() {
expect(JSON.stringify(scope.shapes)).toEqual(JSON.stringify([{"id":1,"name":"Round","created_at":"2014-05-23T17:10:32.000Z","updated_at":"2014-05-23T17:10:32.000Z"},{"id":2,"name":"Cat Eye","created_at":"2014-05-27T18:53:36.000Z","updated_at":"2014-05-27T18:53:36.000Z"},{"id":3,"name":"sharps","created_at":"2014-05-28T21:41:44.000Z","updated_at":"2014-07-02T14:13:59.000Z"},{"id":4,"name":"square","created_at":"2014-06-02T15:29:58.000Z","updated_at":"2014-06-02T15:29:58.000Z"},{"id":5,"name":"Round","created_at":"2014-06-02T15:35:06.000Z","updated_at":"2014-06-02T15:35:06.000Z"},{"id":6,"name":"fffff","created_at":"2014-07-02T14:14:23.000Z","updated_at":"2014-07-02T14:14:23.000Z"},{"id":7,"name":"Rectangular","created_at":"2014-07-29T15:17:01.000Z","updated_at":"2014-07-29T15:17:01.000Z"},{"id":8,"name":"Diamond","created_at":"2014-07-29T15:17:08.000Z","updated_at":"2014-07-29T15:17:08.000Z"}]));
});
it('sets materials', function() {
expect(JSON.stringify(scope.materials)).toEqual(JSON.stringify([{"id":1,"name":"Steel","created_at":"2014-05-23T17:04:42.000Z","updated_at":"2014-05-23T17:04:42.000Z"},{"id":2,"name":"Cotton","created_at":"2014-05-23T17:04:47.000Z","updated_at":"2014-05-23T17:04:47.000Z"},{"id":3,"name":"woods","created_at":"2014-05-28T20:26:16.000Z","updated_at":"2014-07-02T14:35:09.000Z"},{"id":4,"name":"plastic","created_at":"2014-06-02T15:30:05.000Z","updated_at":"2014-06-02T15:30:05.000Z"},{"id":5,"name":"glass","created_at":"2014-06-02T15:34:58.000Z","updated_at":"2014-06-02T15:34:58.000Z"},{"id":7,"name":"wood","created_at":"2014-06-02T16:51:47.000Z","updated_at":"2014-06-02T16:51:47.000Z"},{"id":8,"name":"rubber","created_at":"2014-07-02T14:35:51.000Z","updated_at":"2014-07-02T14:35:51.000Z"},{"id":9,"name":"carbon","created_at":"2014-07-29T14:52:44.000Z","updated_at":"2014-07-29T14:52:44.000Z"},{"id":10,"name":"paper","created_at":"2014-07-29T14:53:31.000Z","updated_at":"2014-07-29T14:53:31.000Z"},{"id":11,"name":"sandpaper","created_at":"2014-07-29T14:56:39.000Z","updated_at":"2014-07-29T14:56:39.000Z"},{"id":12,"name":"xfsdfsf","created_at":"2014-07-29T14:56:44.000Z","updated_at":"2014-07-29T14:56:44.000Z"}]));
});
it('sets color_group_ids', function() {
expect(scope.color_group_ids).toEqual([]);
});
it('sets shape_ids', function() {
expect(scope.shape_ids).toEqual([]);
});
it('sets material_ids', function() {
expect(scope.material_ids).toEqual([]);
});
it('fsdf', function() {
expect(scope.blah).toEqual("ffffff");
});
describe('changeSelectedColor', function() {
it('sets the selected_color attribute of the product', function() {
product = {name: "Product Name"};
color = {name: "Red"};
scope.changeSelectedColor(product, color);
expect(product.selected_color).toEqual(color);
});
});
describe('clearAll', function() {
it('empties the color_group_ids array', function() {
scope.color_group_ids = [1,2,3];
scope.clearAll();
expect(scope.color_group_ids).toEqual([]);
});
it('empties the shape_ids array', function() {
scope.shape_ids = [1,2,3];
scope.clearAll();
expect(scope.shape_ids).toEqual([]);
});
it('empties the material_ids array', function() {
scope.material_ids = [1,2,3];
scope.clearAll();
expect(scope.material_ids).toEqual([]);
});
it('sets selected to false for every object in color_groups', function() {
expect(scope.color_groups.length).toBeGreaterThan(0);
scope.clearAll();
selected_is_false_for_all_color_groups = true;
for (var i = 0; i < scope.color_groups.length; i++) {
var color_group = scope.color_groups[i];
if (color_group.selected) {
selected_is_false_for_all_color_groups = false;
break;
}
}
expect(selected_is_false_for_all_color_groups).toBeTruthy();
});
it('sets selected to false for every object in shapes', function() {
expect(scope.shapes.length).toBeGreaterThan(0);
scope.clearAll();
selected_is_false_for_all_shapes = true;
for (var i = 0; i < scope.shapes.length; i++) {
var shape = scope.shapes[i];
if (shape.selected) {
selected_is_false_for_all_shapes = false;
break;
}
}
expect(selected_is_false_for_all_shapes).toBeTruthy();
});
it('sets selected to false for every object in materials', function() {
expect(scope.materials.length).toBeGreaterThan(0);
scope.clearAll();
selected_is_false_for_all_materials = true;
for (var i = 0; i < scope.materials.length; i++) {
var material = scope.materials[i];
if (material.selected) {
selected_is_false_for_all_materials = false;
break;
}
}
expect(selected_is_false_for_all_materials).toBeTruthy();
});
});
describe("toggleMaterialFilter", function() {
it("when material_ids includes material_id: it removes material_id from material_ids", function() {
scope.material_ids = [1,2,3];
scope.toggleMaterialFilter(1);
expect(scope.material_ids).toEqual([2,3]);
});
it("when material_ids does not include material_id: it adds material_id to material_ids", function() {
scope.material_ids = [2,3];
scope.toggleMaterialFilter(1);
expect(scope.material_ids).toEqual([2,3,1]);
});
});
describe("toggleShapeFilter", function() {
it("when shape_ids includes shape_id: it removes shape_id from shape_ids", function() {
scope.shape_ids = [1,2,3];
scope.toggleShapeFilter(1);
expect(scope.shape_ids).toEqual([2,3]);
});
it("when shape_ids does not include shape_id: it adds shape_id to shape_ids", function() {
scope.shape_ids = [2,3];
scope.toggleShapeFilter(1);
expect(scope.shape_ids).toEqual([2,3,1]);
});
});
describe("toggleColorFilter", function() {
it("when color_group_ids includes color_group_id: it removes color_group_id from color_group_ids", function() {
scope.color_group_ids = [1,2,3];
scope.toggleColorFilter(1);
expect(scope.color_group_ids).toEqual([2,3]);
});
it("when color_group_ids does not include color_group_id: it adds color_group_id to color_group_ids", function() {
scope.color_group_ids = [2,3];
scope.toggleColorFilter(1);
expect(scope.color_group_ids).toEqual([2,3,1]);
});
});
}
What am I doing wrong??? How do I make shared examples for my controllers?
The problem is that you are wrapping an it inside of another it. As javaCity rightfully thought, you cannot do that & need to wrap your call to sharedExamplesForIndexControllers inside of a describe.
However, this causes the second problem you describe with scope being undefined. This is because when the call to sharedExamplesForIndexControllers is actually being called before the beforeEach, while the outer describe is being executed. A such, scope is undefined at that point. What you need to do is defer getting scope until after your beforeEach fires, ideally until you actually need it in your various its.
A way to do this, though perhaps not the cleanest, is to pass a closure that closes over scope into your shared example so that when you execute it inside of your it it has the value that has been assigned by your beforeEach. There might be a cleaner way, but here is a brief example:
describe('ProductsIndexCtrl', function() {
beforeEach(inject(function($controller, $rootScope, $injector) {
scope = $rootScope.$new();
…
ProductsIndexCtrl = $controller('ProductsIndexCtrl', {
'$scope': scope
});
…
}));
//HERE!
it('behaves like an index controller', function() {
sharedExamplesForIndexControllers(function () { return scope; });
});
});
})
shared example:
function sharedExamplesForIndexControllers(scopeGetter) {
it('sets color_groups', function() { expect(JSON.stringify(scopeGetter().color_groups)).toEqual(<expected_value>);

Testing data set on Angular service after $http call

is there a way to test the data that is set on an angular service after a restful call, here is the service I am setting up. It just has two service calls one to fetch for the widgets and the other to get the widgets, If I then run the test to fetch the widgets, I expect the service to have widgets on a success.
angular.module('myApp').factory('myService', function() {
var service, widgets;
widgets = void 0;
return service = {
widgets: widgets,
fetchWidgets: function() {
var promise;
return promise = $http.get('/fetch/widgets').then(function(response) {
return widgets = response;
});
}
};
return service;
});
and the test:
describe('myService', function() {
var $httpBackend, service;
service = void 0;
$httpBackend = void 0;
beforeEach(function() {
module('myApp');
return inject((function(_this) {
return function(_$httpBackend_, myService) {
$httpBackend = _$httpBackend_;
return service = myService;
};
})(this));
});
afterEach(function() {
$httpBackend.verifyNoOutstandingExpectation();
return $httpBackend.verifyNoOutstandingRequest();
});
return describe("fetchWidgets", function() {
return it("should set the widgets on the service", function() {
var responseData;
responseData = [
{
id: 1
}
];
$httpBackend.whenGET('/fetch/widgets').respond(function(status, data) {
return [200, responseData];
});
expect(service.widgets).toBeUndefined();
service.fetchWidgets().then(function() {
return expect(service.widgets).toEqual(responseData);
});
return $httpBackend.flush();
});
});
});
I keep seeing service.widgets as always undefined, but i see the success block being executed. what am I missing?
There are still a few javascript gotchas left to be discovered on this journey. I needed to call a method on the service not directly access the properties. this works:
In the service add this method to access the property:
getWidgets: function() {
return widgets;
},
And in the test you can now access the values
expect(service.getWidgets()).toBeUndefined();
service.fetchWidgets()
$httpBackend.flush();
expect(service.getWidgets()).toEqual(responseData);

Angular Service Definition: service or factory

I am an angular newbie, I am building an application, one thing really puzzling me is there are couple of ways of defining a service, and I read more from this link: How to define service
then it seems there is no big difference among the ways of defining a service.
but I just noticed one difference which I think is different:
see this service I get from here http://jsfiddle.net/2by3X/5/
var app = angular.module('myApp', []);
app.service('test', function($timeout, $q) {
var self = this;
this.getSomething = function() {
return self.getData().then(function(data) {
return self.compactData(data);
});
};
this.getData = function() {
var deferred = $q.defer();
$timeout(function() {
deferred.resolve("foo");
}, 2000);
return deferred.promise;
};
this.compactData = function(data) {
var deferred = $q.defer();
console.log(data);
$timeout(function() {
deferred.resolve("bar");
}, 2000);
return deferred.promise;
};
});
if I define this service using "factory" like below, one function cannot call other functions of the service.
app.factory('test', function($timeout, $q) {
return {
getSomething : function() {
return getData().then(function(data) {
return compactData(data);
});
},
getData : function() {
var deferred = $q.defer();
$timeout(function() {
deferred.resolve("foo");
}, 2000);
return deferred.promise;
},
compactData : function(data) {
var deferred = $q.defer();
console.log(data);
$timeout(function() {
deferred.resolve("bar");
}, 2000);
return deferred.promise;
},
};
});
I will get this in the browser console:
[08:41:13.701] "Error: getData is not defined
.getSomething#http://fiddle.jshell.net/_display/:47
Ctrl1#http://fiddle.jshell.net/_display/:75
invoke#http://code.angularjs.org/1.0.0/angular-1.0.0.js:2795
instantiate#http://code.angularjs.org/1.0.0/angular-1.0.0.js:2805
Can anyone explain this? thanks.
you have two big problems there:
the factory returns an object with incorrect syntax.
javascript scope of variables is functional
That is,
You should be returning an object like {key: value, key: value}
values can be functions. however, you return {key = value, key = value}
First fix:
return {
getSomething : function() {...},
getData : function...
}
Secondly, not being able to call functions is normal. See this jsfiddle. I mocked everything. You can call one of the functions returned by the service. However, when from getSomething try to call getData, you get "undefined":
app.factory('testSO', function () {
return {
getSomething: function () {
console.log('return getsomething');
getData();
},
getData: function () {
console.log('return getData');
}...
This would be the same as declaring everything in the scope of the factory function and return references see in jsfiddle:
app.factory('testSO', function () {
var getSomething = function () {
console.log('return getsomething');
};
...
return {
getSomething: getSomething,
...
}
and now you can call local functions as shown in the final version of the jsfiddle:
app.factory('testSO', function () {
var getSomething = function () {
console.log('return getsomething');
getData();
};
...
The original service has something important in it: var self = this; . Some people use var that = this. It's a workaround for an error in ECMA.
In the case of the original code, it's used to "put everything in one object". Functions (properties that happen to be functions) in self need a reference to know where the function you want to call is. Try it yourself here http://jsfiddle.net/Z2MVt/7/

Resources