Im having problem using $inject.get in angular js..
Let say i have angular services like this
app.service("serviceOne", function() {
this.dialogAlert = function() {
return 'Message One'
};
});
app.service("serviceTwo", function() {
this.dialogAlert = function() {
return 'Message Two'
};
});
app.service("serviceThree", function() {
this.dialogAlert = function() {
return 'Message Three'
};
});
And using the factory to dynamically call dialogAlert()
app.factory("alertService", function($window, $injector) {
if ($window.servicesOne) {
return $injector.get("serviceOne");
} else {
return $injector.get(["serviceTwo", "serviceThree"]);
}
});
With this kind of codes, it gives me "unknown provider".
Or is there any alternative solution for this?
Thanks guys.
injector.get takes only one service name as argument, array is not supported, you may want to do return array of service instances by doing return ["serviceTwo", "serviceThree"].map($injector.get):-
app.factory("alertService", function($window, $injector) {
var service = ["serviceOne"];
if (!$window.servicesOne) {
service = ["serviceTwo", "serviceThree"];
}
return service.map($injector.get); //To be consistent send back this as well as array
});
So with this when you inject the alertService it will return an array of dependecy(ies).
app.controller('MainCtrl', function($scope, alertService) {
// alertService will be array of dependecies.
console.log(alertService.map(function(itm){return itm.dialogAlert()}));
});
Demo
or return with a map:-
app.factory("alertService", function($window, $injector) {
var service = ["serviceOne"],
serviceObjs = {};
if (!$window.servicesOne) {
service = ["serviceTwo", "serviceThree"];
}
angular.forEach(service, function(itm){
serviceObjs[itm] = $injector.get(itm);
});
return serviceObjs;
});
Related
I'm doing unit testing for the first time and I'm trying to work out how to mock a data call from a service so I can test if the data is coming back in the correct form:
My Service
angular.module('app.core')
.factory('PeopleService', PeopleService)
function PeopleService($http, $q, $filter) {
var endpoint;
var service = {
customers: {
value: null
},
getAllCustomers: getAllCustomers,
};
return service;
function getCustomers(endpoint_) {
endpoint = endpoint_;
service.customers.value = [];
return handleFetch($http.get(endpoint));
}
function handleFetch(promise) {
return promise.then(function (resp) {
service.customers.value = service.customers.value.concat(resp.data.data);
});
}
function getAllCustomers() {
return $q.all([
getCustomers('/api/customers'),
]).then(function(responses) {
return responses[0];
});
}
}
My Controller
angular.module('app.people')
.controller('peopleCtrl', peopleCtrl);
function peopleCtrl($scope, PeopleService) {
$scope.customers = PeopleService.customers;
getCustomers();
function getCustomers() {
return PeopleService.getAllCustomers().then(function () {
return PeopleService.customers.value;
});
}
}
My Test
describe('People Service', function () {
var controller;
var customers = mockData.getMockCustomers(); // my fake customers array
beforeEach(function() {
bard.appModule('app');
bard.inject('$controller', '$q', '$rootScope', 'PeopleService');
var ps = {
getAllCustomers: function() {
return $q.when(customers);
}
};
controller = $controller('peopleCtrl', {
$scope: $rootScope,
PeopleService: ps
});
});
it('should return an array of 5 customers', function() {
$rootScope.$apply();
expect($rootScope.customers).to.have.length(5);
});
});
I've got a controller set up that when loaded talks to the People Service and gets my customers and saves the array of customers to PeopleService.customers.value. Inside my controller, I have a variable $scope.customers which is equal to PeopleService.customers.
I'm trying to mock this with my test, without hitting the API, I'm using some mock data to do this (an array of 5 customers), but not sure if I understand correctly.
Is the idea to have my mock people service return exactly what the actual people service returns? I'm kind of confused at this point. I basically want that test to check if the mock data length is equal to five.
Any help with this is appreciated. Thanks in advance!
I'm very new to AngilarJS. I am trying to write a service in angularJS.
<script>
var module = angular.module("myapp", []);
module.service('BrandService', function ($http) {
var brands = [];
this.getBrands = function()
{
return $http.get('http://admin.localhost/cgi-bin/brand.pl')
.then(function(response)
{
brands = response.brands;
alert (brands);
});
}
//simply returns the brands list
this.list = function ()
{
return brands;
}
});
module.controller("brandsController", function($scope, BrandService) {
$scope.brandlist = BrandService.list();
alert ($scope.brandlist);
});
</script>
The statement "alert (brands);" is not getting called. What is the issue with this code. Is m missing any thing in implementation?
$http calls are always async. Meaning, even you do a .then at your service, there is no way it will properly the resolved data back into your controller. You will have to write it in your controller.
Your Service:
module.service('BrandService', function($http) {
var brands = [];
this.getBrands = function() {
//do not need the dot then.
return $http.get('http://admin.localhost/cgi-bin/brand.pl')
}
//simply returns the brands list
this.list = function() {
return brands;
}
});
In your controller:
module.controller("brandsController", function($scope, BrandService) {
BrandService.list()
.then(function(response) {
$scope.brandlist = response.brands;
alert($scope.brandlist);
});
});
In service:
this.getBrands = function() {
$http.get('http://admin.localhost/cgi-bin/brand.pl').then(function(response) {
brands = response.brands;
alert(brands);
return brands;
});
}
In controller:
$scope.brandlist = BrandService.getBrands();
alert($scope.brandlist);
I'm using Facebook connect to login my clients.
I want to know if the user is logged in or not.
For that i use a service that checks the user's status.
My Service:
angular.module('angularFacebbokApp')
.service('myService', function myService($q, Facebook) {
return {
getFacebookStatus: function() {
var deferral = $q.defer();
deferral.resolve(Facebook.getLoginStatus(function(response) {
console.log(response);
status: response.status;
}));
return deferral.promise;
}
}
});
I use a promise to get the results and then i use the $q.when() to do additional stuff.
angular.module('angularFacebbokApp')
.controller('MainCtrl', function ($scope, $q, myService) {
console.log(myService);
$q.when(myService.getFacebookStatus())
.then(function(results) {
$scope.test = results.status;
});
});
My problem is that i need to use the $q.when in every controller.
Is there a way to get around it? So i can just inject the status to the controller?
I understand i can use the resolve if i use routes, but i don't find it the best solution.
There is no need to use $q.defer() and $q.when() at all, since the Facebook.getLoginStatus() already return a promise.
Your service could be simpified like this:
.service('myService', function myService(Facebook) {
return {
getFacebookStatus: function() {
return Facebook.getLoginStatus();
}
}
});
And in your controller:
.controller('MainCtrl', function ($scope, myService) {
myService.getFacebookStatus().then(function(results) {
$scope.test = results.status;
});
});
Hope this helps.
As services in angularjs are singleton you can create new var status to cache facebook response. After that before you make new call to Facebook from your controller you can check if user is logged in or not checking myService.status
SERVICE
angular.module('angularFacebbokApp')
.service('myService', function myService($q, Facebook) {
var _status = {};
function _getFacebookStatus() {
var deferral = $q.defer();
deferral.resolve(Facebook.getLoginStatus(function(response) {
console.log(response);
_status = response.status;
}));
return deferral.promise;
}
return {
status: _status,
getFacebookStatus: _getFacebookStatus
}
});
CONTROLLER
angular.module('angularFacebbokApp')
.controller('MainCtrl', function ($scope, $q, myService) {
console.log(myService);
//not sure how do exactly check if user is logged
if (!myService.status.islogged )
{
$q.when(myService.getFacebookStatus())
.then(function(results) {
$scope.test = results.status;
});
}
//user is logged in
else
{
$scope.test = myService.status;
}
});
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);
I have written a service, depending on an other service. But initialisation is not working.
You can find a plunker as showcase
Should be close to working... Any tipps?
Thanks in advance!
edit: The plunker is fixed now and can be used as reference.
You need to either change your testServiceMockConfig and testService from factory to service, for example:
.service('testServiceMockConfig', function ()
or keep them as factories and add return.this; at the bottom of both of them or restructure them like this (recommended):
angular.module('testServiceMockConfig', [])
.factory('testServiceMockConfig', function() {
console.log("setup cqrs mock config.");
return {
doLoadItems: function(callback) {
console.log("mock loading data");
if (!this.configuredLoadItems) {
throw Error("The mock is not configured to loadItems().");
}
callback(this.loadItemsError, this.loadItemsSuccess);
},
whenLoadItems: function(success, error) {
this.configuredLoadItems = true;
this.loadItemsSuccess = success;
this.loadItemsError = error;
}
};
});
I also assume that loadItems in testService should call:
testServiceMockConfig.doLoadItems(callback);
instead of:
testService.doLoadItems(callback);
As I see from your example,
you didn't define properly the factory. The this key used for service
in testService.doLoadItems(callback); replace with testServiceMockConfig.doLoadItems(callback);
The difference between service - factory - provider and definition you can find in this simple demo:
Fiddle
Fixed example:
angular.module('testServiceMockConfig', [])
.factory('testServiceMockConfig', function () {
console.log("setup cqrs mock config.");
return{
doLoadItems : function (callback) {
console.log("mock loading data");
if (!this.configuredLoadItems) {
throw Error("The mock is not configured to loadItems().");
}
callback(this.loadItemsError, this.loadItemsSuccess);
},
whenLoadItems : function (success, error) {
this.configuredLoadItems = true;
this.loadItemsSuccess = success;
this.loadItemsError = error;
}
}
});
angular.module('testService', ['testServiceMockConfig'])
.factory('testService', ['testServiceMockConfig', function (testServiceMockConfig) {
console.log("mock version. testServiceMockConfig: ");
return {
loadItems : function (callback) {
testServiceMockConfig.doLoadItems(callback);
}
}
}])
angular.module('ItemApp', ['testService'])
.controller('ItemsCtrl', ['$scope', 'testService', function ($scope, testService) {
$scope.text = 'No items loaded';
testService.loadItems(function (error, items) {
if (error) {
$scope.text = "Error happened";
}
$scope.text = '';
for (i = 0; i < items.length; i++) {
$scope.text = $scope.text + items[i].name;
}
})
}]);
Demo Plunker