AngularJs defining global variables - javascript

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.

Related

Handling global variables in Meteor

I'm using a query on both server and client (pub/sub). So I have something like this at a few different locations.
const FOO = 'bar';
Collection.find({property:FOO})
Foo may potentially change and rather than have to update my code at separate locations, I was thinking it may be worth it to abstract this away to a global variable that is visible by both client and server.
I created a new file 'lib/constants.js' and simply did FOO = 'bar; (note no keyword). This seems to work just fine. I found this solution as the accepted answer How can I access constants in the lib/constants.js file in Meteor?
My question is if this a desired pattern in Meteor and even general JS.
I understand I can abstract this away into a module, but that may be overkill in this case. I also think using session/reactive vars is unsafe as it can kinda lead to action at a distance. I'm not even gonna consider using settings.json as that should only be for environment variables.
Any insights?
yes, If you are using older version of meteor then you can use setting.json but for updated version we have import option.
I don't think the pattern is that bad. I would put that file in /imports though and explicitly import it.
Alternatively, you can write into Meteor.settings.public from the server, e.g., on start-up, and those values will be available on the client in the same location. You can do this without having a settings file, which is nice because it doesn't require you to make any changes between development and production.
Server:
Meteor.startup(() => {
// code to run on server at startup
Meteor.settings.public.FOO = 'bar';
});
Client:
> console.log(Meteor.settings.public.FOO);
bar
This is actually a b̶a̶d̶ unfavoured pattern because with global variables you cannot track what things changed and in general constructing a modular and replaceable components is much better. This pattern was only made possible due to Meteor early days where imports directory/pattern was not supported yet and you'd have your entire code split up between both,server and client.
https://docs.meteor.com/changelog.html#v13220160415
You can find many write ups about it online and event stackoverflow answers so I don't want to restate the obvious.
Using a settings.json variable is not an option since we may dynamically change so what are our options? For me I'd say:
Store it the database and either publish it or retrieve it using methods with proper access scoping of course. Also you can dynamically modify it using methods that author DB changes.
Or, you may try using Meteor.EnvironmentVariable. I'd be lying if I said I know how to use it properly but I've seen it being used in couple Meteor projects to tackle a similar situation.
https://www.eventedmind.com/items/meteor-dynamic-scoping-with-environment-variables
Why are global variables considered bad practice?

Why do Services, Constants, Etc Need to be Injected?

Let's say I create an AngularJs service. I attach it to my module:
angular.module('fooModule').service('myService', function(){
var service = {
logSomething: function() {
console.log('Service logged something');
}
};
return service;
});
Whatever. It's there - same with constants, factories, providers, etc. Why do I need to then inject this service, constant, etc into my controllers? Is it essentially the same principle as "using" in C# - the only purpose being avoiding conflicting variable/function names? That doesn't seem to make sense since I still have to write myService.logSomething() which clears up the whole namespace issue.
Or does it somehow speed up loading? I don't see how that would be though.
You haven't actually injected this service into anything yet; it is just a singleton at this point. You have registered it with your angular module, yes, but nothing else in your module knows about it. It's not available until you actually inject it. In a very abstract way, you could think about dependency injection in Angular like using or import, but it's really more like supplying an initializing variable in a constructor (actually, this is exactly what it is).
If you are wondering why dependency injection might be a good design practice in general, this post should be of interest to you.

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.

How should I make configurable modules in AngularJS

I've been tinkering with AngularJS and I've built up a small collection of directives and services that I would like to package into a single JS file so that I can use them anywhere.
I have some website specific settings that my module will need for API calls and that sort of thing. I'm just wondering what the Angular way of making configurable modules is. Obviously I don't want to have to modify my reusable JS file for each website, as that kind of defeats the purpose of having it. Seeing as the values are going to remain the same for each website it seems like an awful lot of hassle to pass them in as an argument on each function call, and I'd rather stay away from global variables as much as possible.
I've searched a lot of questions for the answers I seek, and the closest pattern I've found so far is to have my reusable module be dependant on a not included module called "settings" or something and then define that module in the page's JS file, allowing the reusable module to pull the values from it. Here's an example to show what I mean.
This seems backwards to me. It's kind of like having a function pull values from global values instead of passing the values in as arguments.
Is this really the best way of doing this, or is there an alternative?
It sounds like you're looking for a provider.
You should use the Provider recipe only when you want to expose an API for application-wide configuration that must be made before the application starts. This is usually interesting only for reusable services whose behavior might need to vary slightly between applications.
Here's a very basic example of a provider:
myMod.provider('greeting', function() {
var text = 'Hello, ';
this.setText = function(value) {
text = value;
};
this.$get = function() {
return function(name) {
alert(text + name);
};
};
});
This creates a new service, just like you might with myMod.service or myMod.factory, but provides an additional API that is available at config time—namely, a setText method. You can get access to the provider in config blocks:
myMod.config(function(greetingProvider) {
greetingProvider.setText("Howdy there, ");
});
Now, when we inject the greeting service, Angular will call the provider's $get method (injecting any services it asks for in its parameters) and gives you whatever it returns; in this case, $get returns a function that, when called with a name, will alert the name with whatever we've set with setText:
myMod.run(function(greeting) {
greeting('Ford Prefect');
});
// Alerts: "Howdy there, Ford Prefect"
This is exactly how other providers, like $httpProvider and $routeProvider work.
For more information on providers and dependency injection in general, check out this SO question on dependency injection.

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