Adding an attribute to a provider after config - angularjs

I am using ng-flow, to upload files with a servlet but as I was securing the servlet I realized I need to pass the token to the headers so It would work and be secure. The problem is that ng-flow's settings are declared on a provider inside a .config box. And as I learned the hard way you can't inject stuff on .config because the injections are created after config.
angular.module('UploadModule', [ 'ngResource','flow' ,'AuthModule']).config(
[ 'flowFactoryProvider',function(flowFactoryProvider,$provide) {
//AuthService.getKeycloak();
flowFactoryProvider.defaults = {
target : '/ng-flow-java/upload',
permanentErrors : [ 500, 501 ],
maxChunkRetries : 1,
chunkRetryInterval : 5000,
simultaneousUploads : 4,
progressCallbacksInterval : 1,
withCredentials : true,
method : "octet",
headers : {'Authorization', 'Bearer + ' token}
};
flowFactoryProvider.on('catchAll', function(event) {
console.log('catchAll', arguments);
});
// Can be used with different implementations of Flow.js
// flowFactoryProvider.factory = fustyFlowFactory;
} ]);
I am really new to angular so I am looking for a way reassemble this code so I can add the token from my user.
Thanks

I think I don't understand what exactly is the problem but:
Actually each angular service x has a provider function. This function is a constructor function and will be instanciated by angular and its result is injectable in config blocks with name xProvider. This object should have a special $get function which is actually the factory for the service, meaning that it will be called to get the single instance of the service, when it is injected into some controller, directive, etc for the first time.
So you should think of an angular service as a function like this:
function SomeServiceProvider(){
this.$get = function SomeServiceFactory(){
}
this.someConfigurerFunction(){
}
}
which is registered with provider API:
someModule.provider("someService", SomeServiceProvider);
and angular internally will execute something like new SomeServiceProvider() and save it and makes in injectable in config blocks under the name of someServiceProvider. Further, when you ask for "someService", in a directive, controller, etc, for the first time, the injector will call something like new someServiceProvider.$get(), return its result to you and saves it in its registry for further injections.
When you use other higher level angular module APIs, like factory or service like this:
someModule.factory("anotherService", function AnotherServiceFactory(){
// code for creating service
});
the provider function is generated for you with only a $get function, so you don't see the provider function, but still there is a provider function for your service like this:
function AnotherServiceProvider(){
this.$get = AnotherServiceFactory;
}
and it's used as constructor to instantiate anotherServiceProvider which is injectable in config blocks.
You can find out good information about angular services in angular documentations for $provide and angular documentations for module API
Side Notes:
Good services usually come with a provider that enables you to configure service, but if not, you still can intercept the creation of the service with decorators and make service to work as you want.
The process of instantiating objects like services is not exactly like what I've said here (I mean new ...), but it doesn't changes the concepts described here.

Related

Angular Controller can inject service just fine but $injector.get can't?

I have an extremely edge case scenario where I have a callback method I have to define during config. Which means no scope, no factories, etc... My work around is to use the root injector ($injector) and get my other modules at runtime.
However, when I call $injector.get('myServiceName') in my call back (after the application is running) I get "unknown provider". The same service has no problem (and actually is) being injected into a before my line of code is running. If I call $injector.get("myServiceNameProvider") then I can get the provider back in my callback.. But another service that only has a factory I can't get at all.
So in this extremely bad practice, how can I snag the service I configured. Heck I can't even seem to get $rootScope..
Angular inits providers first, then factories/services - services are not available in app.config.
You can deo like this:
app.config(...
window.on('scroll', function() {
// this is executed later
$injector.get()...
})
Or use app.run where services are available.
I think I had similar problem few months ago... I need to construct breadcrumbs, but they had to be created in config phase (ui-router). I have done it like this (breadcrumbs-generation-service.provider.js):
var somethingYouHaveToHaveLater = undefined;
function BreadcrumbsGenerationService () {
this.createStateData = createStateData;
function createStateData (arg) {
somethingYouHaveToHaveLater = arg;
};
}
function BreadcrumbsGenerationServiceProvider () {
this.$get = function BreadcrumbsGenerationServiceFactory () {
return new BreadcrumbsGenerationService();
}
}
angular
.module('ncAdminApp')
.provider('BreadcrumbsGenerationService', BreadcrumbsGenerationServiceProvider);
Because service is used inside Angular configs, needs to be injected as provider to be available in config phase: Similar SO Question. Despite the fact is registered as BreadcrumbsGenerationService needs to be injected as BreadcrumbsGenerationServiceProvider to config phase and used with $get():
BreadcrumbsGenerationServiceProvider.$get().createStateData(someParams);
But in controller, inject it without Provider suffix (BreadcrumbsGenerationServic) and it behaves as normal service.

Should I attach a config to $rootScope or repeatedly call injected factory?

I have some data in my firebase server that provides settings for client apps.
I've implemented a factory that gets this data from the server.
My question is regarding design - should I get this data once and application start and attach it to rootscope and pass that to all controllers needing it or inject my factory into every controller that uses the config data and internally in the factory store the config locally?
// this factory allows getting various global app settings and constants
.factory('ConfigFactory', ['$firebaseObject', 'FirebaseConfig',
function($firebaseObject, FirebaseConfig) {
'use strict';
var configs = new Firebase(FirebaseConfig.baseUrl + "/configs");
var _configs = [];
return {
getConfig: function(configName, user_id){
if( !_configs[configName]){
_configs[configName] = $firebaseObject(configs.child(configName));
}
return _configs[configName];
}
};
}
])
The good practice is to use a service and inject this service where you need that information.
Note that what you're defining is not a factory, but a service. The factory is the function used to create the service, and the fact that you're using factory() rather than service() or provider() to define this service is an implementation detail.
The service is thus named badly. In should be named "configuration", rather than "ConfigFactory". Services usually start with a lowercase letter.

How to call a service by his name at controller runtime in angularJs?

I am passing the service name from one controller to another controller as argument in angularjs. When I receive that variable in the second controller and use it as service name then I get an error i.e. serviceNameVariable.get is not a function. So my question is that, How can I use a variable as service name in a controller ?
It's not that difficult to get a service by his name.
Dependency injection can also be done at runtime in angular :
angular.module("someApp").controller("childController", [
"$injector",
function($injector){
var serviceName = "someServiceName";
var service = $injector.get(serviceName);
service.executeAction(someParams);
}
]);
Look at Angular's $injector service which allows you to dynamically retrieve your own or native angular modules anywhere:
$injector is used to retrieve object instances as defined by provider, instantiate types, invoke methods, and load modules.
We inject the $injector service like any other:
app.controller('ctrl', function ($injector) {
var serviceNameVariable = '$http'; // or some input
var service = $injector.get(serviceNameVariable);
// Use the 'injected' service, in this case the $http#get method:
service.get('http://endpoint');
});

Modify or access angular interceptors after config phase

Is it possible to access / modify $http interceptors after the config phase? I'm debugging an app that only breaks in production due to being deployed on a different server, so unfortunately I can't change the interceptor code locally and figure out what's going on.
If it's not possible to access / modify the interceptors, perhaps it'd be possible to replace $http. Here's an example of replacing a hypothetical service:
var inj = angular.element('body').injector(),
oldGet = inj.get,
mockService = { secret: 'shhh' };
inj.get = function(str) {
if (str === 'some-service') {
return mockService;
} else {
return oldGet.apply(inj, arguments);
}
};
However, I'm not sure how I'd go about creating a new $http service (into which I could pass in the modified interceptors). I can't grab the $httpProvider, either.
Perhaps bootstrapping a new ng-app on a separate part of the page would work? Then I could grab the $http service and replace it, like above.
Other ideas:
With reference to: Right way to disable/remove http interceptors in Angular? , it does not seem like I can access the interceptors array if I don't hold on to it in the config phase.
Perhaps I can use grease monkey to inject something that runs in the config phase.
Thank you!

Angular JS: why the difference between module.config injection and controller injection?

This is something that I could not figure out from digging into the AngularJS code, maybe you can help solve the mystery.
To show it, I added a service to AngularJS seed project:
function MyServiceProvider() {
console.log('its my service');
this.providerMethod = providerMethod;
function providerMethod() {
console.log('its my service.providerMethod');
}
this.$get = $get;
function $get() {
var innerInjectable = {
name: 'stam'
};
return innerInjectable;
}
}
var serviceModule = angular.module('myApp.services', []).
value('version', '0.1').
provider('myservice',MyServiceProvider);
You can see that this provider exposes $get and a certain 'providerMethod'.
Now, for the injection usage:
If we call config, we can inject the whole class and get access to the 'outer' provider method:
serviceModule.config(function(myserviceProvider) {
console.log('myServiceProvider:',myserviceProvider);
myserviceProvider.providerMethod();
});
But when we inject this to a controller (note the Provider-less name), only the $get return value is exposed:
function MyCtrl1(myservice) {
console.log('MyCtrl1.myservice =',myservice,myservice.name);
}
MyCtrl1.$inject = ['myservice'];
Console output follows as it should:
its my service
myServiceProvider:
Constructor {providerMethod: function, $get: function}
its my service.providerMethod
MyCtrl1.myservice = Object {name: "stam"} stam
Can any one explain the difference? The reason?
many thanks for any thought
Lior
PS: I've seen this technique in angular-ui new ui-router (excellent project!). I need access to the outer provider class to do injection in jasmine and other places - to no avail
A provider is responsible for creating instances. In your example, you created a provider explicitly, but the truth is that every service has a provider, even if it's created automatically for it. [module].service() and [module].factory() are just shortcuts for [module].provider().
[module].config() is run during provider registrations and configurations so you get a change to access providers and do stuff with them. It's a place for configuration of things, hence the name.
From the documentation (http://docs.angularjs.org/guide/module):
Configuration blocks - get executed during the provider registrations
and configuration phase. Only providers and constants can be injected
into configuration blocks. This is to prevent accidental instantiation
of services before they have been fully configured.
Controllers, in the other hand, are instantiated AFTER services have been configured, so you're not supposed to mess with providers anymore. Everything has already been configured. You're ready to get their products now. In this phase, the injector just can't inject providers anymore, just instances (services) created by them.
If you register a service myService...
myModule.service('myService', function() {
// this is your service constructor
});
then you can access its provider, myServiceProvider, in a config function...
myModule.config(function(myServiceProvider) {
// to stuff with your provider here
});
but by the time controllers are being instantiated, you're supposed to ask for services, not their providers, so this will not work...
myModule.controller(function(myServiceProvider) {
...
});
whereas this will be fine...
myModule.controller(function(myService) {
...
});
If you're finding yourself needing to do configuration in a controller, you should stop and rethink the place of responsibilities.
From the Angular mailing list I got an amazing thread that explains service vs factory vs provider and their injection usage. I decided to put it in its own question here
the specific answer is: it is so by design, to allow configuration of the provider at config time.

Resources