can't get service instance from $injector.get() - angularjs

I define a customer service named "greeting", but can't get the instance from $injector.get('greeting'). It will throw such error: Unknown provider: greetingProvider <- greeting. So which is the right way to get it? Following is the code:
var app = angular.module('myDI', []);
app.config(function($provide){
$provide.provider('greeting', function(){
this.$get = function(){
return function(name) {
console.log("Hello, " + name);
};
};
});
});
var injector = angular.injector();
var greeting = injector.get('greeting');
greeting('Ford Prefect');

You need to create the injector from the module.
var app = angular.module('myDI', []);
app.config(function($provide){
$provide.provider('greeting', function(){
this.$get = function(){
return function(name) {
console.log("Hello, " + name);
};
};
});
});
var injector = angular.injector(['myDI', 'ng']); //Add this line
var greeting = injector.get('greeting');
greeting('Ford Prefect');
var injector = angular.injector();
Try it here. FIDDLE

Related

Angular $injector:unpr] Unknown provider:

Working through a test app with a service and I keep getting an error about adding the service using the factory method. Not sure why, i know i am probably staring right at the problem..
The error i get is:
VM497 angular.js:10126 Error: [$injector:unpr] Unknown provider: githubProvider <- github
http://errors.angularjs.org/1.2.28/$injector/unpr?p0=githubProvider%20%3C-%20github
Thanks in advance.
(function() {
var github = function($http) {
var getUser = function(username) {
return $http.get('https://api.github.com/users/' + username).then(function(response) {
return response.data
});
};
var getRepos = function(user) {
return $http.get(user.repos_url).then(function(response) {
return response.data;
});
};
return {
getUser: getUser,
getRepos: getRepos
};
};
var module = angular.module("githubViewer");
module.factory('github', github) ;
});
Controller that injects the service
// Code goes here
(function() {
var app = angular.module("githubviewer", []);
var MainController = function(
$scope, github, $interval,
$log, $anchorScroll, $location) {
var onUserComplete = function(data) {
$scope.user = data;
github.getRepos($scope.user).then(onRepos, onError);
};
var onRepos = function(data){
$scope.repos = data;
$location.hash("userDetails");
$anchorScroll();
}
var onError = function(reason) {
$scope.error = "Could not fetch the Data";
};
var decrementCountDown = function(){
$scope.countdown -= 1;
if($scope.countdown < 1){
$scope.search($scope.username);
}
};
var countDownInterval = null;
var startCountDown = function(){
countDownInterval = $interval(decrementCountDown, 1000, $scope.countdown);
};
$scope.search = function(username){
$log.info("Searching for: " + username);
github.getUser(userName).then(onUserComplete, onError);
if (countDownInterval) {
$interval.cancel(countDownInterval);
}
};
$scope.username = "angular";
$scope.message = "GitHub Viewer";
$scope.repoSortOrder = "-stargazers_count";
$scope.countdown = 5;
startCountDown();
};
app.controller("MainController", MainController)
}());
You need to inject the service into app, from the code you posted. you are not injecting anything into the module.
var app = angular.module("githubviewer", ['yourservice', function(yourservice){}]);
This should get you headed in the right direction.
found my problem, the name of my module had a typo on capitalization. The V in Viewer was wrong.
Controller - var app = angular.module("githubviewer", []);
Service - var module = angular.module("githubViewer");

Is it possible to call factory binded variable in deviceready?

I have following code somewhere in my javascript:
var app = angular.module("App");
app.factory('rest', function($http) {
});
index.js:
document.addEventListener("deviceready", function() {
// How I am able to call rest here?
var domElement = document.documentElement;
angular.bootstrap(domElement, ["App"]);
var $body = angular.element(document.body);
var $rootScope = $body.scope().$root;
$rootScope.$apply(function () {
$rootScope.$broadcast('initialized', 'initialized');
});
});
You can register a run function to your module. So when you will bootstrap your module run will be executed and in the run you will be able to access the factory. Something like this:
// Code goes here
var app = angular.module("App");
app.factory('rest', function($http) {});
app.run(function(rest) {
console.log('your rest factory', rest);
});
document.addEventListener("deviceready", function() {
// How I am able to call rest here?
var domElement = document.documentElement;
angular.bootstrap(domElement, ["App"]);
var $body = angular.element(document.body);
var $rootScope = $body.scope().$root;
$rootScope.$apply(function() {
$rootScope.$broadcast('initialized', 'initialized');
});
});

Unit testing two dependent services and controller in AngularJS

I have a demo application where I have a controller which has a factory as dependency and factory itself depends on another service. My code is as follows:
var app = angular.module('sampleApp', ['ui.router']);
app.service("someServ", function(){
this.sendMsg = function(name){
return "Hello " + name;
}
})
app.factory("appFactory", function ($http, someServ) {
function getData(url) {
return $http.get(url);
}
function foo(){
var text = someServ.sendMsg("Monotype");
alert(text);
}
return {
getData : getData,
foo : foo
}
})
var productsController = function ($scope, $http, appFactory) {
var pct = this;
pct.url = "http://mysafeinfo.com/api/data?list=englishmonarchs&format=json";
var jsonDataPromise = appFactory.getData(pct.url);
jsonDataPromise
.then(function (response) {
pct.jsonData = response.data;
}, function (err) {
console.log("Error is: " + error);
});
pct.profun = function(){
appFactory.foo();
}
};
app.controller("productsController", productsController);
productsController.$inject = ['$scope', '$http', 'appFactory'];
I have to test with karma using Jasmine 2.4 as testing framework. I have tried many online tutorials but getting totally confused as everyone tries to do something different. Some use $provide to mock the service, some simply inject the actual service/factory and use a reference, some do not give any example of passing arguments to services.
Can someone please tell me how to do unit testing in simple terms. I have already tried doing something like this:
describe('unit testing of service and controller', function(){
beforeEach(module('sampleApp'));
var prodCtrl, $prodScope, mockfactory, mockservice;
beforeEach(function(){
mockservice = {
sendMsg : function(name){
return name;
}
}
module(function($provide){
$provide.value("someServ", mockservice);
});
inject(function($rootScope, $controller, $http, $q, appFactory){
appFactory = appFactory;
spyOn(appFactory, 'getData');
spyOn(appFactory, 'foo');
$prodScope = $rootScope.$new();
prodCtrl = $controller('productsController', {
$scope: $prodScope, $http: $http, appFactory:appFactory
});
});
});
it('appFactory has method getData and foo', function(){
appFactory.getData();
appFactory.foo();
expect(appFactory.getData).toHaveBeenCalled();
expect(appFactory.foo).toHaveBeenCalled();
})
it('productsController gets a promise back from getData', function(){
var url = "sample url";
var myPromise = prodCtrl.getData(url);
myPromise.then(function(){console.log("Promise returned");})
})
it('foo calls service method sendMsg', function(){
prodCtrl.profun();
expect(mockservice.sendMsg).toHaveBeenCalled();
})
});
I was finally able to solve this issue. My code looks like this:
var app = angular.module('sampleApp', []);
app.service("someServ", function(){
this.sendMsg = function(name){
return "Hello " + name;
}
})
app.factory("appFactory", function ($q, someServ) {
function getData() {
var defer = $q.defer();
defer.resolve("Success message");
return defer.promise;
}
function foo(){
var text = someServ.sendMsg("Monotype");
alert(text);
}
return {
getData : getData,
foo : foo
}
})
app.controller("mainController", ['$scope', '$http','appFactory', function($scope, $http, appFactory){
var mct = this;
mct.printData = function(){
var myPromise = appFactory.getData();
myPromise
.then(function(data){
alert("Promise returned successfully. Data : " + data);
}, function(error){
alert("Something went wrong.... Error: " + error);
})
}
mct.showMsg = function(){
appFactory.foo();
}
}]);
The test case looked like this:
describe('unit testing', function(){
var jsonData = {
name: "Aosis",
id: 12345
}
beforeEach(module('sampleApp'));
beforeEach(module(function($provide){
$provide.service("someServ", function(){
//this.sendMsg = function(param){}
this.sendMsg = jasmine.createSpy('sendMsg').and.callFake(function(param){})
});
$provide.factory("appFactory", function(someServ, $q){
function getData(){
var defer = $q.defer();
defer.resolve("Success message");
return defer.promise;
}
function foo(){
var facParam = "some text";
someServ.sendMsg(facParam);
}
return {
getData : getData,
foo : foo
}
});
}));
var $scope, mainController, appFactoryMock, someServMock;
beforeEach(inject(function($rootScope, $controller, $http, $q, appFactory, someServ){
appFactoryMock = appFactory;
someServMock = someServ;
$scope = $rootScope.$new();
mainController = $controller("mainController", {
$scope : $scope,
$http : $http,
appFactory : appFactoryMock
});
}));
// Tests go here....
});
Here, I have mocked service method as jasmine spy and specified the function that should get executed usingand.callFake(function(){.....}). A fake factory has been created and its methods have been spied upon. I tried to create fake factory similar to service using jasmine.createSpy but return {
getData : getData,
foo : foo
} was giving error. Hence, I did that.
Anyone, else if has better solution or some other explanation, please share.

Angular global factory

I created a factory that I would like to use in different pages:
var sessionApp = angular.module('sessionApp', ['LocalStorageModule']);
sessionApp.config(function(localStorageServiceProvider)
{
localStorageServiceProvider
.setPrefix('mystorage')
.setStorageType('localStorage');
});
sessionApp.factory('SessionFactory', function(localStorageService)
{
var service = {};
var _store = 'session';
service.load = function()
{
var session = localStorageService.get(_store);
}
service.save = function(data)
{
localStorageService.set(_store, JSON.stringify(data));
}
service.delete = function()
{
localStorageService.remove(_store);
}
return service;
});
Then I would add it on apps run method where I would assign it to the $rootScope. I left that part of the code commented out for now.
var loginApp = angular.module("loginApp", []);
loginApp.run(function($rootScope, SessionFactory)
{
//$rootScope.sessionFactory = SessionFactory;
$rootScope.$on('$routeChangeStart',
function(ev, next, current)
{
});
});
My error is:
Unknown provider: SessionFactoryProvider <- SessionFactory
Is it because my factory is from sessionApp and my login module is loginApp? Does that mean that I need to have the variables named the same like below:
File: login.js
var myApp = angular.module("loginApp", []);
myApp.run(function($rootScope, SessionFactory)
{
//$rootScope.sessionFactory = SessionFactory;
$rootScope.$on('$routeChangeStart',
function(ev, next, current)
{
});
});
File: session.js
myApp.config(function(localStorageServiceProvider)
{
localStorageServiceProvider
.setPrefix('mystorage')
.setStorageType('localStorage');
});
myApp.factory('SessionFactory', function(localStorageService)
{
var service = {};
var _store = 'session';
service.load = function()
{
var session = localStorageService.get(_store);
}
service.save = function(data)
{
localStorageService.set(_store, JSON.stringify(data));
}
service.delete = function()
{
localStorageService.remove(_store);
}
return service;
});
The array argument to angular.module is an array of other modules that you new module depends on. loginApp needs to list sessionApp as a dependency.
var loginApp = angular.module("loginApp", ["sessionApp"]);

AngularJS - Injecting factory from another module into a provider

I have a factory from a separate module that I would like to inject into a provider for my module, but I keep getting unknown provider errors. What am I doing wrong?
What I would like to inject:
var angularSocketIO = angular.module('socketioModule', []);
angularSocketIO.factory('socketio', [
'$rootScope',
'addr',
function($rootScope, addr) {
var socket = io.connect(addr,{
'sync disconnect on unload': true
});
...
return socket;
}
]);
Where I am trying to inject it:
angular.module('myApp.services', ['socketioModule'])
.provider('greeter', ['socketio', function(socket) {
var salutation = 'Hello';
this.setSalutation = function(s) {
salutation = s;
}
function Greeter(a) {
this.salutation = salutation;
socket._emit('hello')
this.greet = function() {
return salutation + ' ' + a;
}
}
this.$get = function(version) {
return new Greeter(version);
};
}]);
That results in
Error: [$injector:modulerr] Failed to instantiate module myApp due to:
[$injector:modulerr] Failed to instantiate module myApp.services due to:
[$injector:unpr] Unknown provider: socketio
I think is because all the providers are instantiated before the factories and so a provider has to depend only on other providers.
As a way around that, I am using the injector method of angular.module to create the module.
A plunker that should do what you were trying to accomplish: http://plnkr.co/edit/g1M7BIKJkjSx55gAnuD2
Notice that I changed also the factory method. The factory method is now returning an object
with a connect method.
var angularSocketIO = angular.module('socketioModule', ['ng']);
angularSocketIO.factory('socketio', [
'$rootScope',
function($rootScope) {
return {
connect: function(addr) {
var socket = io.connect(addr, {
'sync disconnect on unload': true
});
return socket;
}
};
}]);
angular.module('myApp.services', ['socketioModule'])
.provider('greeter', [
function() {
var injector = angular.injector(['socketioModule']);
var socketio = injector.get('socketio');
var salutation = 'Hello';
this.setSalutation = function(s) {
salutation = s;
}
function Greeter(a) {
this.salutation = salutation;
socket._emit('hello');
this.greet = function() {
return salutation + ' ' + a;
};
}
this.$get = function(version) {
return new Greeter(version);
};
}
]);
var myApp = angular.module('myApp', ["myApp.services"]);
I think you can add dependencies via $get method in provider:
angular.module('myApp.services', ['socketioModule'])
.provider('greeter', [
function() {
...
this.$get = ['socketio', function(socket, version) {
function Greeter(a) {
this.salutation = salutation;
socket._emit('hello')
this.greet = function() {
return salutation + ' ' + a;
}
}
return new Greeter(version);
}];
}
]);

Resources