I wonder how can i use factory inside a provider for using it inside config.
Since i understand config can be injected only with providers - i wonder how can i achieve the following functionality
app.provider('getUserLanguageProvider',['$injector', function($injector) {
this.$get = function(getUserLang) { // calling a factory
var userLang = getUserLang.getLang()
return {
getLang: function() {
return userLang
}
}
};
}]);
app.config(['$translateProvider', 'getUserLanguageProvider', function ($translateProvider, getUserLanguageProvider) {
const lang = getUserLanguageProvider.getLang() // get the language key from provider
$translateProvider.preferredLanguage(lang); // set the language key brought by getUserLang.getLang() factory
}]);
I've tried many versions of what i've described - but none works.
Don't append Provider to the provider name. Simply use the name of the service:
̶a̶p̶p̶.̶p̶r̶o̶v̶i̶d̶e̶r̶(̶'̶g̶e̶t̶U̶s̶e̶r̶L̶a̶n̶g̶u̶a̶g̶e̶P̶r̶o̶v̶i̶d̶e̶r̶'̶,̶[̶'̶$̶i̶n̶j̶e̶c̶t̶o̶r̶'̶,̶ ̶f̶u̶n̶c̶t̶i̶o̶n̶(̶$̶i̶n̶j̶e̶c̶t̶o̶r̶)̶ ̶{̶
app.provider('getUserLanguage',['$injector', function($injector) {
this.$get = ['$http', function($http) { // calling a factory
var userLang = getUserLang.getLang()
return {
getLang: function() {
// ....
}
}
}];
}]);
The $injector service will automatically append the Provider suffix to the configuration object. The configuration object will then be injectable into .config functions as the name of the service appended with Provider as a suffix.
Related
I"m very new to Angular and I'm having problems configuring IdleProvider and KeepaliveProviders. Please understand the question: I've already configured those two providers correctly and my idle timeout is working. What I'm looking for is how to provide values to those providers by reading such values from a properties file. I've been able to read values from a properties file but I'm unable to pass them to the providers in my .config() method.
I'm using angular 1.4.3 (pls don't ask me to upgrade - I just joined a project where they are using this.
Here's my config method in route.js
define(['app'], function(app) {
'use strict';
return app
.config(function($stateProvider, $urlRouterProvider, $httpProvider, KeepaliveProvider, IdleProvider) {
console.log("Idle timer is here")
IdleProvider.idle(5); //Rather than hardcoding, I want to pass from a property file
IdleProvider.timeout(5); //Rather than hardcoding, I want to pass from a property file.
KeepaliveProvider.interval(10); //Same here - pass from a property file
I have a Service class where I read my property file and set the result in $sessionStorage but I'm not able to inject the sessionStograge into the .config(..) method above because you can only inject constants and providers into .config(..). Any help would be appreciated!
auth.getRedirectUrls2 = function() {
console.log("getRedirectUrls2 has been caled!!");
var promise = $http.get("resources/sessiontimeout.properties")
.then(function(response) {
console.log("In getRedirectUrl2 response is: ", response.data);
console.log("Is the damn data in the session or not: ", $sessionStorage.redirectprops);
$sessionStorage.redirectprops = response.data;
return response.data;
})
.catch(function(response) {
console.error('Gists error', response.status, response.data);
})
.finally(function() {
console.log("In getRedirectUrls2 - Finally, all is done!!");
});
$sessionStorage.redirectpromise = promise;
console.log("The promise is: ", promise);
console.log("The promise from session is: ", $sessionStorage.redirectpromise);
return promise;
};
=======Edited with follow-up questions ====
I have the following project structure but don't know where to create the provider.
webapp/static/app/js
controllers (all controllers here)
directivers (all directives here)
services (all services here)
Also, can I create tryConstant.layouts.idleTime inside the provider constructor like this?
layout.idleTime=xyz
layout.intervalTime=abc
Where do I inject $sessionStorage or the service in the provider?
You should create a provider and use the provider in the config, you can use the service and sessionStograge in the provider and you can use provider in the config.
Here's a example of provider:
(function() {
'use strict';
angular
.module('app')
.run(layoutRunner)
.provider('tryConstant', constantProvider);
function constantProvider() {
var layout = {};
}
function constanntRunner() {
// check for $stateChangeStart and update the layouts if we have data.layout set
// if nothing set reset to defaults for every state
var destroyOn = $rootScope.$on('$stateChangeStart');
$rootScope.$on('$destroy', removeWatch);
function removeWatch() {
destroyOn();
}
}
})();
And you can use sessionstorage and everything here, and update values in layout object. And use it in config as following
.config(function($stateProvider, $urlRouterProvider, $httpProvider, KeepaliveProvider, IdleProvider,tryConstant ) {
console.log("Idle timer is here")
IdleProvider.idle(tryConstant.layouts.idleTime);
}
Since this change, you can use setIdle and setTimeout functions on Idle service to change these values after service has been configured.
I had the same scenario and solved it using factory providers, as below:
angular.module()
.factory("myFun", ['$http',
function($http){
return {
getAppIdleDuration: function() {
return $http.get("/api/property/getAppIdleDuration")
.then(function(response) {
return response.data;
});
},
getAppIdleTimeout: function() {
return $http.get("/api/property/getAppIdleTimeout")
.then(function(response) {
return response.data;
});
}
};
}
]).config(function(IdleProvider, KeepaliveProvider,myFunProvider) {
myFunProvider.$get().getAppIdleDuration().then(function(data){
console.log(" ++++++ getAppIdleDuration "+data);
IdleProvider.idle(data); // in seconds
});
myFunProvider.$get().getAppIdleTimeout().then(function(data){
console.log(" ++++++ getAppIdleTimeout "+parseInt(data));
IdleProvider.timeout(parseInt(data)); // in seconds
});
})
Configs in application.properties:
app.ui.idle.duration=5
app.ui.idle.timeout=10
Here /api/property/getAppIdleDuration and /api/property/getAppIdleTimeout http calls return the above properties respectively.
when I use a service function to define a service in angularjs, can I return a object like the following code
angular.module('myApp').service('mySerivce',function(){
return {
add: function(){};
};
});
I cannot find any document about this programming style.
Make sure you understand the syntax of factory and service
factory:
angular.module('myApp').factory('myFactory',function(){
return {
add: function(){};
};
});
service:
angular.module('myApp').service('myService',function(){
this.add = function () {};
});
I recommend that you read the following Angular style guide.
https://github.com/johnpapa/angular-styleguide
Adding some more detail here (excerpt from style guide)
Services are instantiated with the new keyword, use this for public methods and variables. Since these are so similar to factories, use a factory instead for consistency.
Note: All Angular services are singletons. This means that there is only one instance of a given service per injector.
// service
angular
.module('app')
.service('logger', logger);
function logger() {
this.logError = function(msg) {
/* */
};
}
// factory
angular
.module('app')
.factory('logger', logger);
function logger() {
return {
logError: function(msg) {
/* */
}
};
}
// factory
angular
.module('app')
.factory('logger', logger);
function logger() {
return {
logError: function(msg) {
/* */
}
};
}
In angular services are singletons, which means there is only ONE instance of that service. There are cases where you would want unique instances of objects. This is where the Factory Pattern comes in handy.
https://en.wikipedia.org/wiki/Factory_method_pattern
Within angular this pattern can most easily be seen with the $resource factory. With the $resource factory you request a unique instance of a resource.
In Angular services are classes. They are constructor functions. But only one instance is ever newed up. So a factory allows you to new instances as needed.
// my service
function Foo(fooId) {
this.id = fooId;
}
function fooFactory() {
return function(id) {
return new Foo(id);
}
}
angular.module('app').factory('foo', fooFactory);
So in the above if we delete the factory and just bind Foo to the DI container with angular.module('app').service('foo', Foo) -- what will happen? Every instance of Foo will have the same id. But with this factory, we can set the id when we create the instance.
So why use the factory and not just new up the instance by myself? Testability. Your code is not testable if you new up your classes (yes a constructor is just a class, in a sense) in your services or controllers.
Do you need this? Probably not for much.
You should just use services.
function Bar($http, $timeout) {
this.$http = $http;
this.$timeout = $timeout;
}
Bar.prototype.doSomething = function(value) {
return this.$http.get('/api/dosomthing', {value: value});
}
angular.module('app').service('bar', Bar);
I read about how to inject dependency in cofing method of the module. I created provider for my service like this
app.provider("securitySvc", function securitySvcProvider () {
this.$get = ['Authorizations', '$q', 'routeSvc', function securitySvcFactory (Authorizations, $q, routeSvc) {
return new securityService(Authorizations, $q, routeSvc);
}];
});
When I try to use it I get instance with a $get method instead of newed up securityService. What am I doing wrong?
app.config( ['$routeProvider', 'routes', 'securitySvcProvider', routeConfigurator]);
function routeConfigurator($routeProvider, routes, securitySvc) {
// HERE securitySvc is instance with a $get method, not newed up securitySvc
}
Note that everywhere else, in controllers, securitySvc is injected correctly.
However, if do follwing in "run" method of module
app.run(function ($rootScope, securitySvc) {
$rootScope.hasPermission = function (authorizationName) {
return securitySvc.hasAuthorization(authorizationName);
};
}
Then if I reference it in routeConfiguration through $rootScope.hasPermission it works fine. My goal was to avoid using scope and just use service. Can it be done?
Although question was why instance of the provider is injected into config method of the module and PSL explained it in comments, what I really wanted was to find out how to use service in config method. Here is how I achieved what I wanted. I added a method on the provider that provides the check I needed.
app.provider("securitySvc", function securitySvcProvider() {
var me = this;
me.$get = ['Authorizations', '$q', 'routeSvc', function securitySvcFactory(Authorizations, $q, routeSvc) {
me.service = new securityService(Authorizations, $q, routeSvc);
return me.service;
}];
me.hasRoutePermission = function(routeName) {
return me.service.hasRoutePermission(routeName);
}
});
Since this check is attached to "resolve" object on the router, I can be sure that service will by then be instantiated.
currently i provide my application with a constant called "config" to inject some specific application-wide configuration like the API endpoint URL and so on.
This works like expected for my main module "app" in the configuration section.
app.config(['config', function(config) {
console.log(config.api); // http://api.endpoint.com
}];
The problem is, that i have a separate module like "app.auth" where i wish you configure it with some values from this global constant, but there i get an error, that the config is unknown.
How i can solve this? Inject a service in the configuration area isn't a solution because AngularJS don't provide the services on the configuration block.
Thank you in advance.
First off you answer your question about why 'config' is not available to your app.
Is your app set as a dependency of 'app.auth'?
var app = angular.module('myApp', ['ngResource']);
var authApp = angular.module('myApp.auth', ['myApp']);
Secondly using a constant to set multiple values is a poor use of constant, that would be a great job for a provider. Here is an example:
module.provider('GlobalConfig', function ($resourceProvider) {
var valOne = 'Some Default';
this.setOne = function(value) {
valOne = value;
};
var valTwo = 'Another Default';
this.setTwo = function(value) {
valTwo = value;
};
this.$get = function($resource) {
return {
getOne: function() {
return valOne;
},
getTwo: function() {
return valTwo;
}
};
};
});
From a .config the provider above can be injected by using 'GlobalConfigProvider' and only the setters would be available. Then for directives and services 'GlobalConfig' can be injected and only the getters would be available.
I know that angular services are singeltons but I have an application in which I want that each directive instance will have a different service object which will hold context. How can it be achived?
You can use a factory that returns the constructor the class that you need, later just inject it to the controller and instantiate it.
app.factory('demoClass', function() {
return {
sayHello : function() { console.log('hello') }
}
});
At controller:
function myController($scope, demoClass)
{
var test = new demoClass();
test.sayHello();
}