Angular circular dependency: best practices for handle it - javascript

I have UserService and GroupService in my app and it make sense that both services will know each other and use each other functions.
There are several tools in angular that give me to "fix" the circular dependency warning.
But everywhere it is written that if you have circular dependency, it's a sign that you have bad architecture.
So, what is the good architecture for cases like that? Why is it right to force (quite forcibly) one of the services not to know the other?

So the problem is when one service need to be instantiated, inside constructor it will require second service. But that second service in order to be instantiated, inside constructor it will require first service.
What you can do is move all the logic from these 2 services into one "parent" service, and use this "parent" service through the application.

you have 2 options:
Extract commonly needed parts of the logic into some SharedModule
If some part of any modules logic is required in other modules then it doesn't belong into that feature module but in top level module (the one that starts the app, does core app things and loads other feature modules).

Related

Using same service with providedIn: root as singleton and providers of component with the service

I would like to know what happens if the following criteria happen.
Created a service as single-ton with providedIn property as root. So that it will be available to the application globally. At the same time, providers meta data in component or module set to the created service. Can any one tell me what is the effect on this situation?
To get more about Singletons you need to refer to official documentation.
Answering your question its quite simple. Singletons are globals for entire application and share the same data. For example, you have a service which adds a script to the head or authentication service which holds global auth status - you need to ensure that they have only one instance across entire application.

Angular 5 global components and their services

Looking through Angular's docs, specifically the style guide, they lay out both a shared module and a core module. According to the docs, services should be placed in the core module and components in the shared module. My question is if I have a component, say a custom file upload component, and it also has a corresponding service, where should that component and service reside? It seems to make sense to keep the two together since the service is used with the component, however, this doesn't seem to follow Angular standards. Anyone come across this issue?
According to Angular Style Guide, Angular doesn't really recommend providing a service in the SharedModule. The reason for that is, whichever module imports the SharedModule, will get a separate instance of that shared service. This isn't really acceptable in case of a Stateful Service. But in your case, I'm not really sure if the Service will contain any state data. So I think, it should be safe for you to add this Component and this Service to the SharedModule itself.
Again, considering that this service is not going to have any state data.
Also, Angular recommends providing services inside the CoreModule because it also recommends making the CoreModule only importable by just a single module(generally the AppModule). That's why it also recommends creating a Guard to prevent re-importing of the CoreModule.
Look up to Providers and singleton-services. In usual way that:
if you want singleton service you must provide it in root module, e.g: router
if you need service instance per component instance, then you provide that service in component definition, and you can pass that service instance to all child components:
#Component({
/* . . . */
providers: [UserService]
})
In case of yours example: if every upload component needs new instance of service, service is defined as #Injectable class, imported to upload component source and registered as a provider in component decorator providers section.
This is a good question and I've got it constantly asked by colleagues in my company. As you said the best practice in official docs is to have CoreModule and SharedModule that each in charge of different concerns. Most of the time it makes sense to put your services into "Core" and components/directives/pipes etc. into "Shared".
But sometimes we do have exceptions and want to do the following:
A service in SharedModule to manage the states/configurations/behaviors for the counterpart components/directives/pipes
A component in CoreModule that only exists in the root level or dynamically created during runtime.
For scenario 1 you can have the legacy forRoot() method for your module to make sure your service only gets initialized once. Also it's worth mentioning that with Angular 6 you can use the new provideIn: 'root' syntax which simplifies this purpose. You can find many resources online.
For scenario 2 you usually put it into entryComponents.

AngularJs defining global variables

What is the best way to define a global varible in AngularJS?
I know there are plenty of solutions about this topic, the most commom:
Use a service;
Use $rootScope;
I want an answer for a different context. For example:
A commom url used for multiple requests in multiple services: my/folder/class.php;
The name of a main module: myApp;
A commom alert message for an error: Failed to connect to the server, try again.
Things that will be used all over the app, in different situations and will never change.
Looking around the internet I saw 2 other possibilities other then $rootScope and services:
Use AngularJS constants;
Use JS var outside of the main ng module;
So my question is: For the AngularJs scenario, what is the best alternative?
Do we really use constants for this situation? Is there any other provider for this purpose. Also I'd like to know whats the performance impact of the, if any.
For true constants use Angular constants. If your values may need to be configured or calculated use an Angular service and expose getter functions. For strings you may want to consider localization, so use one of the Angular localization libraries to store these (I use Angular-localize).
Hope this is helpful.

Managing globally needed services in web applications

I struggle to find a statisfying solution on how to expose service instances whose methods need to be accessed through multiple parts of my applications.
The situation
First things first, by a 'service', I mean an instance of a function that holds properties & methods which are exposed through an API.
Consider a REST service whose purpose it is to provide convenient methods to access REST points on a server. I would make the following assumptions on that service:
It must be available throughout the application. It is likely that as the app grows, there will be new components that need access.
There is no need of multiple instances of this service. We can consider it a singleton.
My solutions
I can think of 2 possible solutions:
Concatenating scripts & utilizing the global object
I could combine all my script files (e.g rest.service.js, app.js) into a single file and create an object property on the global object (like App).
Then, I could attach service instances to this object. This allows me to do something like this from everywhere within the app:
App.restService.get()
However, even if I wrap each service in an IIFE, i still have to add some variables on window in order to retrieve instances.
Using commonJS / AMD modules
I could require() my service instances from everywhere by using require.js / browserify
The issues
Now I got a headache because on the one hand, people are telling me that polluting the global object is bad practice. Singletons are bad practice also.
On the other hand, we make a lot of effort to 'uglify' scripts, each byte saved considered an enhancement. Using browserify would lead to the same script injected in multiple files, though (I'm using web-components, therefore I've got a lot of isolated scripts). Not mentioning the fact that I have no idea on how to provide a state-safe service using browserify.
So how should I approach this problem?
How should I expose standard services that may or may not be instantiated multiple times? How should I implement state-safe ones?
Just a starting point (but too long to be a comment) I really enjoy the strategy used by AngularJs, where you always instantiate services within a container - and every time you instantiate something you also specify which modules should be injected into it:
angular.module('myApp.services', []); // the second argument are the dependencies (an empty array
At any point, you can retrieve your modules and add functionalities:
var services = angular.module('myApp.services');
services.factory('yourServiceName', //
['other', 'service', 'dependencies'],
function(other, service, dependencies){
other.doStuff();
service.doStuff();
dependencies.doStuff();
[..]
});
You can then inject your module in other modules
var myApp = angular.module('na', ['yourServiceName'])
In angular, the app is instantiated by the framework itself - but I guess you can develop a entry point for your app, so that you can use your services.
..unfortunately, I do not know exactly how this pattern is implemented - probably all the modules are stored within an instance of the application, so the global namespace is not polluted.
This problem also confuses me a lot, I think there are two points I can figure out:
1) There must be an entry point for each service in global, otherwise it is impossible to get the one you need everywhere. It's not good to add many things in global, but I think service reference is the one deserved.
2) Config the service object other than initialization, for example, they can be only one ajax service object with different configuration to do different things. There are objects, so they can be merged and extended.
This is an interesting topic, I would like to see more opinions about, not just management of services, also other resources like templates, objects, files, etc.

AngularJS - module().provider() vs $provide.provider()

Note: I'm not seeking the differences between the value, factory, service, and provider 'recipes', as explained here.
I'm looking for clarification on the different ways to define them: Correct me if I'm wrong, but it appears as though
myApp = angular.module('myApp', [])
.value(...)
.factory(...)
.service(...)
.provider(...)
map to
$provide.value()
$provide.factory()
$provide.service()
$provide.provider()
And you can use either way. I asked this question, and realize I can use $provide as a dependency to module().config(). My questions:
When/why would I use angular.module().provider() vs using the $provide dependency?
Is there any way (or reason) to access/change a provider after definition?
Using AngularJS Batarang for Chrome, I'm looking at the various angular $scope properties, and don't see $provide or $injector. Where do these live?
The provider methods off the module definition are just short cuts. Use them as often as you like because it leads to shorter, easier to read and understand code. Less ritual/ceremony is involved than injecting the $provider service and calling that directly. The main reason to use $provide directly is to access a method on it that is not a short cut from module (such as the decorator) or if you have to do something from within a service or component that is not up at the module definition level.
The common case for changing a provider after it's definition is when you are integrating a third-party component and want to add or change the behavior. The third-party module will define the service and then you step in and override or extend it in some way that is specific to your app. A common case for example is to take the built-in Angular exception handler and extend that to interface with your own components.
$scope is a special "glue" used for data-binding and only exposes properties/functions that you explicitly set on the $scope. All of the other miscellaneous modules/services are stored within Angular's dependency injection container. The very first thing Angular does is create an $injector instance to keep track of dependencies. Therefore $injector === $injector.get('$injector'). Same with $provide. Anything prefixed with a $ is by convention a service that Angular places in the $injector for you to use.

Categories