I've created an angular Provider which is exposing a getSession method which I need to resolve before going into a specific route:
var serviceId = 'session';
angular.module("app").provider(serviceId, sessionProvider);
function sessionProvider() {
this.session = undefined;
this.$get = function($http) {
return {
getSession: function () {
return $http.get("/session-info")
.then(_onSuccess, _onError);
}
}
}
function _onSuccess(data) {
return data.data;
}
function _onError(data) {
return data;
}
}
I then inject it into my config and try to use it:
angular.module("app").config([
"$routeProvider", "$httpProvider", "sessionProvider", function
($routeProvider, $httpProvider, sessionProvider) {
$routeProvider.when("/", {
templateUrl: "app/home/home.html",
resolve: {
session: sessionProvider.getSession()
}
});
}
]);
But I get the following error:
Uncaught Error: [$injector:modulerr] Failed to instantiate module app due to:
TypeError: undefined is not a function
I'm not sure what I've done wrong here?
Edit
When I try #DrogoNevets answer below:
function sessionProvider() {
this.session = undefined;
this.$get = function ($http) {
return {
}
}
this.getSession = function () {
return $http.get("/session-info")
.then(_onSuccess, _onError);
}
function _onSuccess(data) {
this.session = data.data;
return data.data;
}
function _onError(data) {
return data;
}
}
I get the following error as I'm not able to inject $http into the provider itself, is that correct?
Uncaught Error: [$injector:modulerr] Failed to instantiate module app due to:
ReferenceError: $http is not defined
if you want to call getSession from the config part you need to assign it to this not within the $get part
try something like this:
function sessionProvider() {
var session;
this.$get = function() {
return {
getSession: this.getSession,
setSession: this.setSession
}
}
function _onSuccess(data) {
return data.data;
}
function _onError(data) {
return data;
}
this.getSession= function () {
return session
}
this.setSession= function (id) {
session = id;
}
}
here is a fiddle showing what I mean: http://jsfiddle.net/EQ86N/1/
Related
I have a problem when trying to call a variable outside a function
This is the service
app.factory('Service', function($http) {
return {
agentes: function () {
return $http.get(base_url +'/api/auth/organization/me/tasks/calendar').then(function (response) {
return response.data;
});
}
};});
within the controller I call:
loadAgents();
function loadAgents() {
Service.agentes()
.then(function(agentes){
$scope.agentes = agentes.data.trackables;
});
}
within the above function I can use $scope.agentes but not outside it ...
I dont understand exactly what is your problem but you have some "mistakes" in your code.You should do
app.factory('Service', function($http) {
return {
agentes: function () {
return $http.get(base_url +'/api/auth/organization/me/tasks/calendar');
}
}
});
Then inside your controller
app.controller('myController', ['Service', function(Service) {
function loadAgents() {
Service.agentes()
.then(function(agentes){
$scope.agentes = agentes.data.trackables;
});
}
}])
I want to develop a generic translator component with configurable url and paramsFn. Here paramsFn can either be a plain function or a function with service dependencies. paramsFn is expected to return a promise.
(function () {
"use strict";
angular.module("translator-app", [])
.provider(translatorProvider);
function translatorProvider() {
var
url,
paramsFn;
//Provider Config Functions
function setUrl (pUrl) {
url = pUrl
};
function setParamsFn (pParamsFn) {
paramsFn = pParamsFn;
};
function factory ($http, $q) {
//Service Function Pseudo
function translate(key) {
if (translateions are cached) {
//return promis of cached translations
} else {
/*
make http call with configured url and
paramsFnto fetch translations.
Cache translations.
Return promise with translations.
*/
}
} //translate
//Service Object
return {
translate: translate
};
} // factory
factory .$inject = [
"$http"
"$q"
];
//Exposed functionality
this.setUrl = setUrl;
this.setParamsFn = setParamsFn;
this.$get = factory;
}
}();
An application can use translator after configuring it. User app provide will be able to provide paramFn with service dependencies. paramFn will be invoked later when translator.translate(...) method is called.
(function () {
"use strict";
angular.module('the-app', ["translator-app"])
.config(translatorConfigurator)
.controller(AppController)
function translatorConfigurator (translatorProvider) {
function theParamsFn (someService) {
//use someService to generate and return params object
}
theParamsFn.$inject = [
"someService"
];
translatorProvider.setUrl("/url/to/translator");
translatorProvider.setParamsFn(theParamsFn);
}
function AppController (translator) {
translator.translate("the-key").then(function (translated) {
//do somethid with 'translated'.
});
}
translatorConfigurator.$injec = [
"translatorProvider"
];
AppController.$inject = [
"translator"
];
}());
How can I achieve this?
Short Story:
According to Angular $injector documentation
// inferred (only works if code not minified/obfuscated)
$injector.invoke(function(serviceA){});
// annotated
function explicit(serviceA) {};
explicit.$inject = ['serviceA'];
$injector.invoke(explicit);
// inline
$injector.invoke(['serviceA', function(serviceA){}]);
Novel
Once upon a time there was a poor translatorProvider. Angular, a great super hero, helped translatorProvider to be feature rich by its $injector weapon. translatorProvider built its getParameters function inside factory function and used it in translate.
(function () {
"use strict";
angular.module("translator-app", [])
.provider(translatorProvider);
function translatorProvider() {
var
url,
paramsFn;
//Provider Config Functions
function setUrl (pUrl) {
url = pUrl
};
function setParamsFn (pParamsFn) {
paramsFn = pParamsFn;
};
function factory ($injector, $http, $q) {
function getParameters() {
var
promise,
fn;
if (paramsFn) {
fn = $injector.invoke(paramsFn);
promise = $q.resolve(fn());
} else {
promise = $q.resolve()
}
return promise;
}
//Service Function Pseudo
function translate(key) {
if (translateions are cached) {
//return promis of cached translations
} else {
getParameters()
.then(function (params) {
return $http({
url: url,
params: params
});
})
.then(function (response) {
var extracted = ...; //extract field from response.data
//put extracted into cache
return $q.resolve(extractedField)
});
}
} //translate
//Service Object
return {
translate: translate
};
} // factory
factory .$inject = [
"$injector",
"$http"
"$q"
];
//Exposed functionality
this.setUrl = setUrl;
this.setParamsFn = setParamsFn;
this.$get = factory;
}
}();
Now translator can be configured as below.
(function () {
"use strict";
angular.module('the-app', ["translator-app"])
.config(translatorConfigurator)
.controller(AppController)
function translatorConfigurator (translatorProvider) {
function theParamsFn (someService) {
return function () {
//returns some parameters object
}
}
theParamsFn.$inject = [
"someService"
];
translatorProvider.setUrl("/url/to/translator");
translatorProvider.setParamsFn(theParamsFn);
}
function AppController (translator) {
translator.translate("the-key").then(function (translated) {
//do somethid with 'translated'.
});
}
translatorConfigurator.$inject = [
"translatorProvider"
];
AppController.$inject = [
"translator"
];
}());
After these changes translatorprovider becomes more powerful and help many other modules and they lived happily ever after.
I'm triying to make a controller/service for a state that get via my own query-method a list of clients.
It's weird because the "getAll" method works perfectly, the problem is query or some other get method... anyway, here is the service:
(function() {
'use strict';
angular
.module('omi.services')
.factory('cliente', clienteFactory);
clienteFactory.$inject = ['$http'];
function clienteFactory ($http) {
var baseUrl = 'http://localhost:3000/omi/v1/clientes/';
var service = {
create : create,
getAll : getAll,
getOne : getOne,
query : query,
remove : remove,
update : update
};
return service
function create (clienteData) {
// body...
} // end create
function getAll () {
return $http.get(baseUrl)
.success(getAllComplete)
.error(getAllOnError);
function getAllComplete (data) {
return data;
}
function getAllOnError (data) {
return data;
}
}
} // end facturaFactory
function getOne (cliente) {
return $http.get(baseUrl + cliente)
.success(getOneComplete)
.error(getOneOnError);
function getOneComplete (data) {
return data;
}
function getOneOnError (data) {
return data;
}
} // end getOne
function query (query) {
return $http.get(baseUrl + 'buscar' + query)
.success(queryComplete)
.error(queryOnError);
function queryComplete (data) {
return data;
}
function queryOnError (error) {
return data;
}
} // end query
function remove (factura) {
// body
} // end remove
function update (clienteData) {
// body...
} // end update
})();
it's not complete yet, but is the entire structure. So, the problem is fired in the controller:
(function(){
'use strict';
angular
.module('omi.controllers')
.controller('clientReportsResult', clientReports);
clientReports.$inject = ['$stateParams', 'cliente'];
function clientReports ($stateParams, cliente) {
/* jshint validthis: true */
var vm = this;
vm.clientes = [];
var id = $stateParams.data;
var query = "?id=" + id;
fire();
function fire () {
cliente.query(query).then(function(data) {
vm.clientes = data.data.clientes;
});
}
}
})();
It fire me this traceback:
"Error: $http is not defined
query#http://localhost:8080/js/services/clientes.service.js:55:7
fire#http://localhost:8080/js/controllers/clientes.reports.results.js:21:9
clientReports#http://localhost:8080/js/controllers/clientes.reports.results.js:18:7
invoke#http://localhost:8080/js/libs/angular/angular.js:4182:14
instantiate#http://localhost:8080/js/libs/angular/angular.js:4190:27
$ControllerProvider/this.$get</<#http://localhost:8080/js/libs/angular/angular.js:8449:18
$ViewDirectiveFill/<.compile/<#http://localhost:8080/js/libs/angular-ui-router/release/angular-ui-router.js:3897:28
invokeLinkFn#http://localhost:8080/js/libs/angular/angular.js:8213:9
nodeLinkFn#http://localhost:8080/js/libs/angular/angular.js:7722:1
compositeLinkFn#http://localhost:8080/js/libs/angular/angular.js:7075:13
publicLinkFn#http://localhost:8080/js/libs/angular/angular.js:6954:30
updateView#http://localhost:8080/js/libs/angular-ui-router/release/angular-ui-router.js:3839:23
$ViewDirective/directive.compile/<#http://localhost:8080/js/libs/angular-ui-router/release/angular-ui-router.js:3807:9
invokeLinkFn#http://localhost:8080/js/libs/angular/angular.js:8213:9
nodeLinkFn#http://localhost:8080/js/libs/angular/angular.js:7722:1
compositeLinkFn#http://localhost:8080/js/libs/angular/angular.js:7075:13
compositeLinkFn#http://localhost:8080/js/libs/angular/angular.js:7078:13
publicLinkFn#http://localhost:8080/js/libs/angular/angular.js:6954:30
$ViewDirectiveFill/<.compile/<#http://localhost:8080/js/libs/angular-ui-router/release/angular-ui-router.js:3905:9
invokeLinkFn#http://localhost:8080/js/libs/angular/angular.js:8213:9
nodeLinkFn#http://localhost:8080/js/libs/angular/angular.js:7722:1
compositeLinkFn#http://localhost:8080/js/libs/angular/angular.js:7075:13
publicLinkFn#http://localhost:8080/js/libs/angular/angular.js:6954:30
updateView#http://localhost:8080/js/libs/angular-ui-router/release/angular-ui-router.js:3839:23
$ViewDirective/directive.compile/</<#http://localhost:8080/js/libs/angular-ui-router/release/angular-ui-router.js:3801:11
$RootScopeProvider/this.$get</Scope.prototype.$broadcast#http://localhost:8080/js/libs/angular/angular.js:14702:15
transitionTo/$state.transition<#http://localhost:8080/js/libs/angular-ui-router/release/angular-ui-router.js:3218:11
processQueue#http://localhost:8080/js/libs/angular/angular.js:13170:27
scheduleProcessQueue/<#http://localhost:8080/js/libs/angular/angular.js:13186:27
$RootScopeProvider/this.$get</Scope.prototype.$eval#http://localhost:8080/js/libs/angular/angular.js:14383:16
$RootScopeProvider/this.$get</Scope.prototype.$digest#http://localhost:8080/js/libs/angular/angular.js:14199:15
$RootScopeProvider/this.$get</Scope.prototype.$apply#http://localhost:8080/js/libs/angular/angular.js:14488:13
done#http://localhost:8080/js/libs/angular/angular.js:9646:36
completeRequest#http://localhost:8080/js/libs/angular/angular.js:9836:7
requestLoaded#http://localhost:8080/js/libs/angular/angular.js:9777:1
" "<div ui-view="" class="details ng-scope">"
I'm triying to solve the problem, but i can't understand the problem, why this error appear's here? In the others controllers where i use the "getAll" method all is working fine!
The getOne function is outside of your clienteFactory factory function where $http is defined, and getAll is in the scope.
This is the structure you have:
function clienteFactory ($http) {
function getAll () {
}
}
function getOne () {
// $http is not defined here
}
Same is happening with query.
Put getOne and query inside the clienteFactory:
function clienteFactory ($http) {
function getAll () {
}
function getOne () {
}
function query() {
}
}
My Angular 1.3 application is using the angular-translate library. In my Karma tests I'm attempting to mock the $translate provider with a Mock object I have created.
The mock object is called MockTranslate and it belongs to the myMocks module. I'm not including the source for MockTranslate in the question as it's not relevant to the question.
The subject of my test is a controller and I can quite easily mock $translate using the following:
module('myMocks');
inject(function($controller, MockTranslate) {
$controller("MyController", {
$translate: MockTranslate.create(translations);
});
});
The above mocking works, however my preference would be to mock the provider using the angular.mock.module with something like:
module('myMocks');
module("myModule", function($provide) {
$provide.provider("$translate", function(MockTranslate) {
return MockTranslate.create(translations);
});
});
But I get the following error when I run my tests:
Error: [$injector:modulerr] Failed to instantiate module function ($provide) due to: Error: [$injector:unpr] Unknown provider: MockTranslate
How do I mock a provider using angular.mock.module?
If I understood the task correctly then here is a working example:
angular.module('translateApp', [])
.controller('translateCtrl', function ($scope, $translate) {
$scope.translate = function(message) {
return $translate.translate(message);
};
})
.provider({
$translate: function() {
this.$get = function () {
return {
translate: function (msg) {
return 'OriginalTranslate: ' + msg;
}
};
};
}
});
describe('Translate Controller Test', function() {
var mockScope;
var mockTranslate;
beforeEach(module('translateApp', function($provide) {
$provide.provider('MockTranslate', function() {
this.$get = function () {
return {
translate: function (msg) {
return 'MockTranslate: ' + msg;
}
};
}
});
$provide.provider('$translate', function() {
this.$get = function (MockTranslate) {
return {
translate: function (msg) {
return MockTranslate.translate(msg);
}
};
}
});
}));
beforeEach(inject(function($controller, $rootScope, $translate) {
mockScope = $rootScope.$new();
mockTranslate = $translate;
$controller('translateCtrl', {
$scope: mockScope,
$translate: mockTranslate
});
}));
it('Translates messages', function () {
expect(mockScope.translate('cool message')).toEqual('MockTranslate: cool message');
});
});
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