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.
Related
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.
Hello TypeScript/Angularists!
TL;DR
Can I pass angular dependencies to a TypeScript module/class, so that those dependencies DON'T become attributes of class objects - instead, they are available through scope function parameters?
I know the recommended way of declaring things in angular/typescript is to create a TS class inside a TS module and release it as an angular service, because:
it can't be a factory (see this)
it's good to have modules
a class (comparing to a plain function) might be used to check compile-time types in typescript
An example of such approach is below:
/// <reference path="../../project.d.ts" />
module project.core.services {
export class UiRoutes {
static $inject = ['$state'];
constructor(private $state: angular.ui.IStateService) {
}
public reloadCurrentView(): void {
this.$state.go(this.$state.current.name, this.$state.params, {
reload: true
});
}
}
}
project.core.CoreModule.service('UiRoutes', project.core.services.UiRoutes);
Anyway, there is one great problem with that approach and that is - I'm forced to pass all angular dependencies into class constructor to make them object attributes (available everywhere, not encapsulated - because if the object is accessible then all it's attributes are accessible).
As an alternative, there is Backbone.js + Require.js example:
define(['jquery', 'use!backbone','models/model'], function($, Backbone, Model){
View = Backbone.View.extend({
//...
});
return new View();
});
where, as you can see, jquery, backbone and some internal stuff is available, but it's not saved as an object attribute - it's available through scope. This is purely natural JavaScript way of doing things - passing things through scope function parameters. In this situation, you can encapsulate more things and your code becomes less verbose. And, mainly, it's good to have a choice rather than to be forced to follow the only right rule.
Now I know that backbone is different than angular and, moreover, DI is totally different than require.js, blah blah blah.
What I want is a an example (or just a design) that allow me to specify all angular dependencies and make them accessible for a TypeScript module/class but not to make them attributes of class objects. This is possible with pure AngularJS (without TypeScript) afterall, so it might be possible along with TypeScript.
PS I'll happily provide better description of the problem, if it's not clear (comments, please). Buit I'm not really interested in answers like "it's not what you want, but it works for me, try this" :) if the answer is "no, that's not possible", than I'd appreciate a proof and/or reasons why.
because if the object is accessible then all it's attributes are accessible
This may be true from a runtime perspective, but the runtime perspective is not the only one that matters. If you're using TypeScript and you mark the injected services as private, then no one is accessing these things unless they're being actively malicious. And odds are extremely good that your code is already not resilient to malicious actors inside its own runtime environment (trivially, someone who wanted to screw with your app could inject in any Angular service and overwrite its properties with their own).
So in that regard, the best thing to do is to not care about what things happen to be on a object somewhere versus in a closure somewhere.
Now I know that backbone is different than angular and, moreover, DI is totally different than require.js, blah blah blah.
To expand on "blah blah blah", a relevant difference here is that your requirejs module is effectively a singleton, whereas your Angular classes usually aren't (most of them are probably controllers).
We need to go back to the object vs closure difference to understand why that matters. If you're going to have closure privacy over your injected services (because compile-time privacy wasn't good enough for whatever reason), it follows that every instance of your object is going to need its own set of subclosures to be able to access those closed-over values.
Duplicating your function closures for every single instance of an object incurs a large performance penalty when there are many instances of the object. It's more allocations, more memory pressure, more time spent cleaning up things in the GC, more time spent marking or sweeping or refcounting in the GC, less locality of reference, less efficient JIT, and so on. This is why TypeScript and other languages don't give you ready-made footguns for making closure-based classes.
Now you're saying "But my service is a singleton!" and you're right. Singletons can be written as a closure like this:
module project.core.services {
export function UiRoutes($state: angular.ui.IStateService) {
function go() {
$state.go(/* etc*/);
}
function other() { }
function foo() { }
return {
go,
other,
foo
}
}
}
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.
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.
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.