Angular 2 Value Providers - Values set from API call at initialization - dependency-injection

I need to provide a date format to our application. We use this to set the format for all display and input of dates.
I need to provide this in numerous places to the application. However, the date varies depending on the client. We have an API call that provides a variety of settings (one of which is the date config) as a JSON object.
I want to be able to provide an object representing the configuration options as a value via DI. There are lots of examples of providing values, but they are all static rather than dynamic.
I want to do something like this in my DI composition root
provide('DateFormat', {
useValue: 'dd/MM/yyyy'
})
However, I want 'dd/MM/yyyy' to come from settings at startup.
I have tried providing it via services, but it is causing issues with race conditions in a few places (value not available when one service runs). Some of this could be solved by re-writing it using more observables, but it just makes the code more complex. So I want some way to provide the object via DI and have the values set before doing anything else.
Any ideas how to achieve this?

If you provide the service in the bootstrap, or in the providers:[] in the root component of your app it will instantiate the service. In the service constructor you can get the data via the api.
If you need to wait until it loads before the first page shows, you could have one observable that indicates the data is loaded or not. Use that observable to route to a new component by subscribing to the observable. Or depending on the structure of your app, use *ngIf on the boolean observable set by the service to show an initialization screen until the api call returns and the data is initialized.
Any other component that needs that configuration can use that instance of the service by injecting via the constructor args.
import {ConfigurationService} from 'path/to/configuration-service';
#Component({
selector : '',
providers: [ConfigurationService] <<-- This instantiates a new
uninitialized service. Do this only in the root component.
})
export ComponentNeedingDateFormat() {
constructor(private configurationService: ConfigurationService) { }
}
If you include it in component providers: [] it will instantiate a new service. You want to inject it only in the root component.
https://angular.io/docs/ts/latest/guide/dependency-injection.html

Related

Angular2 - Retrieving already cached instances from the root/app injector

Is there a reliable way to retrieve already created instances from the root injector? My use case is that I need to instantiate a type myself (with the new construct) but when setting up said type I need to grab two Angular2 Injector-managed instances.
app: ApplicatinRef;
Where the above app variable is retrieved via DI itself.
const rootInjector: Injector = app.injector;
rootInjector.get(SomeInstance);
When I use the above code the SomeInstance type will be instantiated a second time and I was expecting it to retrieve the same instance created during bootstrapping.
Do note, however, when I call
rootInjector.get(SomeInstance);
multiple times after initially calling it, it will not instantiate it again. So it only instantiates twice: during bootstrapping process and when calling upon the injector itself the first time.
There are no other providers for SomeInstance in the DI hierarchy, only specified at application level when bootstrapping.
Am I missing something?
You don't need to get the injector at this way, angular already inject the injector. If you don't provide in any other place the instance will be the same to all components in the hierarchy. Also you don't need to use the injector directly you could ask for the instance of your service in the constructor, like this:
...
constructor(private serviceInstance : ServiceClassName){
this.serviceInstance.doSomething();
}
If you provide in your main component, this instance will be the same in all components:
import { provide } from '#angular/core';
...
bootstrap(..., provide(ServiceClassName, {useClass : ServiceClassName}));
But you could add this instance in any place of your hierarchy using the providers configuration paramater:
import { provide } from '#angular/core';
...
#Component({
...
providers : [provide(ServiceClassName, {useClass : ServiceClassName})]
})
Providing like this will create an instance just for this component and his sub-components.

Inject an application level Service to #CanActivate

I want to achieve a similar function as Angular1.x routing "resolve" did, by using the #CanActivate routing life-cycle event.
As the trigger for allowing the route to pass, I want to use a service, defined in the application bootstrap (which makes it a single application-wide instance).
bootstrap(AppComponent, [
ROUTER_PROVIDERS,
TestObjectModel
])
The only way I see I can use a dependency within that life-cycle event is by using the following:
const injector = Injector.resolveAndCreate([TestObjectModel]);
const testObjectModel = injector.get(TestObjectModel);
That indeed gets me an instance of the service, but a new one (not the instance used application-wide).
I tried Injector.fromResolvedProviders as well with no better results.
Is there any way I can get my hands on the root Injector inside a component?
I've found this workaround at: http://embed.plnkr.co/SF8gsYN1SvmUbkosHjqQ/.
It works and allows me to get the single service instance in life-cycle hooks as well.

using angular factory in multiple controllers

I am using angular ui grid. At first I implemented this in a controller and it works fine after all my customization. As I am using multiple grids I cannot write a long controller each time. So, I converted it to factory. I kept the common function in factory and column definition and data in controller. Now when I use this factory in more than 1 controllers, the last controller is overriding all others.
1) Is it correct to make this grid in a factory?
2) If yes how do I overcome this problem?
3) By using factory for this grid, my gridObj.gridApi.pagination.on is throwing error(gridObj is the singleton object that I am returning).
Any suggestion is welcome. Thanks a lot in advance.
You should use a Directive instead. Factories create a single Instant (see Angular Provider Documentation and wont create a private scope, which you need to not override your data.
Note: All services in Angular are singletons.
But Directives provide a private scope and create new instances every time they are called in HTML if you want them to.
//directive
scope: { // this option creates isolated scopes
something : '=',
},
I created a Plunkr showcasing a possible setup. For some more written details please see my answer from few days ago.
Your HTML might look like this afterwards
<my-grid options="all.firstOptions" class="grid"></my-grid>
Where my-grid is your directive and options="" are your special settings (and whatever else you wish to use in the directive). In your directive you declare the default settings and merge them with the special ones.
scope.gridOptions = {
data: scope.options.data, //private scoped from options : '=',
columnDefs: scope.options.colDef || defaultColDef, // optional setting or default setting
// ... some more default data
};
If you have any specific questions, let me know.

How to create two configured instances of the same service?

I have a service that interacts with a brokerage account's API. It works fine, but now I need to interact with two different accounts at the same brokerage.
It seems like the best way to handle this is to make it possible to configure the service to specify the target account and then instantiate two different instances, one for each account.
I'm not sure if this is supported in Grails or how to go about it.
Two questions:
Is there a better way to do this?
If not, how can I instantiate and configure two different service instances?
ADDITIONAL INFORMATION:
Both answers are near misses. Let me try to clarify:
I didn't want to get into the details, but it may help to explain what I'm after. I'm using the Interactive Brokers trading API, and they don't let you talk directly to their servers the way other brokerages do. You have to talk over a socket to their IB Gateway, which is a piece of software they provide that essentially proxies their servers. So your app talks to IB Gateway, and IB Gateway talks to Interactive Brokers' servers on your app's behalf.
The catch is that IB Gateway has to be logged in to an account as part of its configuration. So, in order to trade two different accounts, you have no choice but to configure two different IB Gateways, since each can only access the account that it is configured for.
So my Grails code for placing trades must select the right IB Gateway to talk to. That means it needs to know the IP address and port of the IB Gateway that corresponds to each account. Other than this setting for IP address and port, there is no difference between the two Grails services that communicate with IB Gateway.
What I want is to reuse the same service class, each being instantiated as a singleton, simply having a different IP address and port on which to communicate.
So making two different services is undesirable, since the code is otherwise identical. (And if I add a third or fourth IB Gateway, this becomes fairly smelly code.)
And this setting should exist for the life of the application, so I don't think a change in scope is really the answer, either.
I really want two instances of the same service, simply having different configurations.
I hope that helps explain the situation. What do you suggest? Thank you!
If the same business logic is applicable for both accounts but taking into consideration that you cannot have a single service class talking to the API for both accounts, then yes you can have 2 service classes (which are nothing but 2 different spring beans) with the default singleton scope.
class Account1Service{
}
class Account2Service{
}
I would also try if I can use inheritance here in this case, if I have common logic that can be shared across. But keep in mind, if you are inheriting a service class from an abstract class then the abstract class has to be placed in src/groovy that is, outside /grails-app/ to defy Dependency Injection. In that case you might end up with (untested, but you can adhere to DRY concept)
// src/groovy
abstract class BrokerageService {
def populateAccountDetails(Long accountId)
def checkAccountStatus(Long accountId)
}
//grails-app/services
class Account1Service extends BrokerageService {
//Implement methods + add logic particular to Account1
//By default transacitonal
}
class Account2Service extends BrokerageService {
//Implement methods + add logic particular to Account2
//By default transacitonal
}
Also keep a note that the scope is singleton, you would take extra care (better avoid) maintaining global scoped properties in Service class. Try to make as stateless as possible. Unless otherwise the situation or the business logic demands to use service level scopes like session, flow or request, I would always stick to the default singleton scope.
To answer your second question, you do not need to instantiate any of the grails service class. The container injects appropriate service class (using Spring IoC) when an appropriate nomenclature is used. In the above example, the service classes will automatically be injected if you follow this naming convention in classes where you wan tto use the services:
//camelCase lower initial
def account1Service
def account2Service
UPDATE
This is in response to the additional information provided by OP.
Referring to the above scenario, there can be only one service class in the default singleton scope to handle things perfectly. The best part, since you are going out of your network and not really worried about own database transactions the service class can be set to non-transactional. But again it depends on the situations need. Here is how the service class would look like.
//grails-app/service
class BrokerageService{
//Service method to be called from controller or any endpoint
def callServiceMethod(Long accountId){
.......
doSomethingCommonToAllAccounts()
.........
def _ibConfig = [:] << lookupIBGatewayConfigForAccount(accountId)
........
//Configure an IB Gateway according to the credentials
//Call IB Gateway for Account using data got from _ibConfig map
//Call goes here
}
def doSomethingCommonToAllAccounts(){
........
........
}
def lookupIBGatewayConfigForAccount(accountId){
def configMap = [:]
//Here lookup the required IP, account credentials for the provided account
//If required lookup from database, if you think the list of accounts would grow
//For example, if account is JPMorgan, get credentials related to JPMorgan
//put everything in map
configMap << [ip: "xxx.xx.xx.xxx", port: 80, userName: "Dummy"] //etc
return configMap
}
}
The scope of the service class is singleton which means there will be only one instance of the class in the heap, which also means that any class level property (other than methods) will be stateful. In this case, you only deal with methods which will be stateless and would suffice the purpose. You would get what you need without spending heap or without creating new instances of BrokerageService every time a trading happens.
Each trade (with an account assciated) will eventually call the service, lookup the credentials from db (or config properties, or flat files, or properties files) and subsequently configure the IB Gateway and call/talk to the gateway.
Grails services are supposed to be singletons by default, not having any state associated to what it is doing and usually only one instance. Namely, you wouldn't have instance fields in them, normally.
But if you override the default scope, you can have them. For example, you can make your service to be session scoped, adding this static variable:
static scope = "session"
Then you'll have one instance for each user session.
For your particular case, you may want to take a look at the prototype scope, which will give you a new instance of the service each time you need it injected. You just will have to make sure to always use that instance after it is injected, if you want them to act on the same data.
Take a look at the docs about Scoped Services.

Is the loadModules.post in zf2 a function?

When I trace the code in zf2 , I can't find where the Application service registers.
Here is the code in application.php
public static function init($configuration = array())
{
$smConfig = isset($configuration['service_manager']) ? $configuration['service_manager'] : array();
$serviceManager = new ServiceManager(new Service\ServiceManagerConfig($smConfig));
$serviceManager->setService('ApplicationConfig', $configuration);
$serviceManager->get('ModuleManager')->loadModules();
return $serviceManager->get('Application')->bootstrap();
}
The code "$serviceManager->get('Application')" is to get the Application service. But where did the application service register?
Then I find that the Application service is related with the code line "$this->getEventManager()->trigger(ModuleEvent::EVENT_LOAD_MODULES_POST, $this, $this->getEvent())" in ZF2/library/Zend/MoudleManager/MoudleManager.php
public function loadModules()
{
if (true === $this->modulesAreLoaded) {
return $this;
}
$this->getEventManager()->trigger(ModuleEvent::EVENT_LOAD_MODULES, $this, $this->getEvent());
/**
* Having a dedicated .post event abstracts the complexity of priorities from the user.
* Users can attach to the .post event and be sure that important
* things like config merging are complete without having to worry if
* they set a low enough priority.
*/
$this->getEventManager()->trigger(ModuleEvent::EVENT_LOAD_MODULES_POST, $this, $this->getEvent());
return $this;
}
The another question is that "ModuleEvent::EVENT_LOAD_MODULES_POST,That is loadModules.post.The first param of the trigger function is a function name. So is the loadModules.post a function ? where was it defined ?
Thanks in advance.
I'll address the last question first. The first param of the trigger method is not a function, it's simply a name; by convention, that name usually mirrors the method in which it is triggered, optionally with a suffix to give more context (such as ".pre", ".post", etc.).
"loadModules.post" is an event that is triggered by ModuleManager::loadModules() once all modules have been loaded. When an event is triggered, any listeners on that event will then be triggered with the parameters provided. The event object itself will also have a "target", which will be the ModuleManager in this case.
Regarding the "Application" service, you have to look into the internals of the MVC layer.
Most MVC services are defined in Zend\Mvc\Service\ServiceListenerFactory. If you look in that class, you'll see that it assigns Application to use the Zend\Mvc\Service\ApplicationFactory to create an Application instance. The ServiceListenerFactory is retrieved as part of the factory that creates the ModuleManager. It's a little indirect, but the relations are defined by the order of operations and the relations between the objects.
Most of the Zend\ServiceManager\ServiceManager registered service are configured by the ServiceListener factory Zend\Mvc\Service\ServiceListenerFactory when creating a ServiceListener instance.
The default config is actually stored in ServiceListenerFactory::defaultServiceConfig.
(If you go through the code you'll see that the 'Application' Alias is being defined there)
For you second question, the ModuleEvent::EVENT_LOAD_MODULES is just one of the ModuleEvent constants that are used to identify the different Modules loading events.
There are actually four module Events triggered at different stages by the application. I didn't have yet the opportunity to use those events, and I think that they're mostly used by the framework itself. So far, I had opportunities to use Zend\Mvc\MvcEvent related events only.

Resources