I'm new to AngularJS. I'm currently looking at the services. Some of these services look like the replace functions already available in JavaScript. For instance, the $timeout service. Why does AngularJS have these services? Is there a technical reason? Are there any advantages to this approach? I just don't understand the need for using these services.
Thank you for any help.
A service is a function or an object, with a set of methods, that could be used by several components (controllers, directives, filters, other services) of your application.
The main advantage that "wrapping" services like $timeout or $window have over their global functions equivalent is that they're injected by Angular, and can thus be mocked in unit tests, i.e. replaced by fake implementations.
Read the chapter about dependency injection in the angular documentation. Regarding the $timeout service in particular, its documentation explains what it does in addition to the native setTimeout() function.
Angular uses dirty check -- it keeps track of all variables that should be updated automatically and in case of any changes iterates through them as many times as needed (as there can be interdependence between observing variables). (To be precise if there are too many iterations something wrong is probably with your code and exception is raised).
The main reason behind $timeout is to signal to Angular engine that you will be making some changes to the observing variables in the callback. In case you would call normal timeout there is a way to inform Angular about those changes by calling e.g. $scope.$apply(function() {...}).
The other big reason, as #JB Nizet stated is that mocking is much easier.
Service is a way to store persistent information over your application.
unlike the $scope, which is an new child of $rootScope per each route\controller.
The purpose of the Angular-specific implementation of already existent functions, is to make your life and work easier, by automatically telling angular to register your changes, and apply them to the current scope at the next $digest iteration.
I'll be happy to address any other questions.
Good luck with Angular! :)
I will now create an example plunk to emphasize the idea to you
UPDATE:
This is the plunker:
http://plnkr.co/edit/mVmhZpEdsZDQ0MUQpFJ7?p=preview
I used ng-change and the native change
keyup event to explain the point.
while using the angular built in ng-change directive requires no additional effort nor code, using the native events requires wrapping everything in the scope.$apply function/
calling scope.$digest manually.
(run the code and see for yourself)
Check out this older answer which covers Services, Providers and Factories.
AngularJS: Service vs provider vs factory
Related
Disclaimer : I know there are certain questions which suggest not to access scope inside service or factory but here I am expecting the impact in terms of coding guidelines / whether it is advisable if not then I need proper justification.
We have angular js project and this project is old. Now after refactoring one of my colleague moved the common implementation from directive to service. While doing so , to access the scope of directive he manually started doing as below :
angular.element('<test-dir></test-dir>').scope();
What I felt is this is not the proper way to write the service/factory. I felt we are making the things complicated and suggested to remove the above part of code.
To justify the same I told :
1. This will make unit testability complicated and now we are trying to test the service the way we used to test directive.
2. And we are making this service tightly coupled with directive.
3. Service is not meant to access the scope.
But I think I am not able to convince him as I don't have much point to justify it. Can someone please suggest if I my understanding is correct and give proper justification to convice him. Thanks!
No, the services/factory are supposed to be working with data and should have the logic to process the data provided to them. Preferably, they should not refer to DOM objects or scope variables.
I personally believe that passing $scope to a service is a bad idea, because it creates a kinda circular reference: the controller depends on the service and the service depends on the scope of the controller.
On top of being confusing in terms of relations, things like this one end up getting in the way of the garbage collector.
A Service is just a function for the business layer of the application. It acts as a constructor function and is invoked once at runtime with new, much like you would with plain JavaScript (Angular is just calling a new instance under the hood for us).Use a service when you want to just create things that act as public APIs.
The service class should work on the data provided by the controller, making it reusable at any other place if needed. Also keeping the scope away from it, keeps the code lean and clean thus better maintainability.
I prefer to put a domain object in the controller scope and pass that to the service. This way the service works irrespective of it being used inside a controller or maybe inside another service in the future.
I am taking over a big (50+ modules) AngularJS project, from another programmer, which did not do it right, so I have several migration questions:
There are lots of usages of JS functions like setTimeout and setInterval. It will be very easy to change to $timeout and $interval (because they use the same syntax, so it is just find and replace), but should I bother?
The entire project is without services, and all data requests run in the controllerss. Should I make time to create services for all controllers, the most important ones, or none? (I know that "if it works dont fix it", but from your experience does this make your life easier?)
The ENTIRE project uses $.ajax, with over a thousand requests. I do not have the time to migrate all requests to use $http, but I will try over time. In the meanwhile, should I create a service like $http_o and replace all "$.ajax(" strings in all files to $http_o, so the service will pretty much get a normal ajax request syntax, and send it using the $http service.
Every controller's services are written in a variable name, and not with a string at the start (function($scope) instead of ['$scope', function($scope)). Is there a fast way to change all of them to use the normal syntax, so I can use a minifier, or do I have to do it by hand? Should I do it?
I will obviously try my best to rework modules to use correct MVC and angular rules in my spare time at work, but this will happen way ahead in the future.
It's not as trivial as you might think i.e. $interval applies a $rootScope.$apply() at end so it will trigger $digest cycle, with lots of intervals it might slow down app
It's all about readability and maintainability. I'd say yes, do separate services and DRY the application otherwise when you will have to debug it in 3 months time it's going to be hell
A smart regex could work for you although the advantage of using $http over $.ajax is that you don't have to use tricks to trigger change in view - i.e. manually run $digest or $apply
You can do it easily with https://github.com/olov/ng-annotate
I am learning to write unit tests for my angular app. My controller has several dependencies upon Resources, factories, services etc
angular.module('app').controller('Ctrl1',['$scope','Factory1','Factory2','Resource1','Resource2' ... and so on
The Resource1, Resource2, etc of course fetch data from the server. Several of these resources are used to fetch data from the server and initialize $scope.
After reading innumerous tutorials all over the net, I have a few queries on the right way to write my jasmine tests
In the beforeEach section of the jasmine test, am I suppose to provide all dependencies right away or should I provide only the ones I care about testing
What I want to test is that Resource1 gets called and fetches some data and intializes some part of $scope then Resource2 gets called and fetches some data and initializes some other part of scope etc
What is the right way to perform the above. I mean am I actually suppose to fetch the data in the test or should I be using some mock http service. I know tutorials mention that we should use mock http service but then how will this test my controller since I am not actually fetching the right data.
This part is really confusing and I have yet to find a blog/article that explains this clearly (I might just write one once I figure things out.. I am sure others are confused too)
Where to Provide Dependencies
You should provide all of your dependencies in your first beforeEach statement. I mock/fake mine with SinonJs. This helps you take advantage of angular's dependency injection to isolate each piece of your application. You should never call a dependency and expect an actual instance of it to return data in a unit test, as that would increase the coupling of your code and make it far more brittle.
Mocking Resource Calls
For resource calls, I simply create a fake resource object with promises and whatnot included. You can then resolve or reject those promises and provide fake data to test your controller logic.
In the plunk below, I've essentially mocked out a whole promise chain. You simply tell your tests to either reject or resolve those promises, faking a successful or failure call to the resource. You then have to make sure your scope cycles with scope.$apply(). I actually forgot to do this which caused me quite a bit of trouble just now.
Conclusion
Here is the Plunk. Let me know if you need to see how I test the actual resource code in my repositories. In those services I have to actually mock out the HTTP calls, which Angular makes extremely easy.
I'm not sure any of this is "Best Practice" but it has worked for me. I learned the basics from looking at other people's source code and watching this Pluralsite video AngularJS Fundamentals which has a very small section on testing.
Useful Resources
Testing AngularJS Directives. This is the hardest thing to test and understand in Angular. Or at least it was for me.
This one is on Dependency Injection in Angular. I have it marked
about where they start talking about unit testing.
This Plural Sight Course got me started with testing JavaScript in general. Very helpful for learning Jasmine if you are new to it.
AngularJS Github repo is very useful if you want to see Jasmine tests in action. Here is a set of tests that simulates a HTTP Backend.
What is the best way to use a third party library in Angular without exposing a global variable?
For instance, if I were using underscore.js, I want to inject _ into only the controllers that use it.
angular.module('module').controller(function(_) {
// _ is injected only into this scope
};
To get this effect, I've seen some people load underscore globally with a script tag, then create a service like this:
myModule.factory('_', function ($window) {
return $window._;
});
However, this still pollutes the global scope with _.
Is there an 'Angular way' of registering and injecting third party libraries without causing this problem?
You can't do anything about how the third party libraries are written, except by forking them and creating your own version.
Third party libraries will almost always create such variables on the global scope, and you mention the two most frequently used ways of using them in an Angular module: by injecting $window and using them directly, or by creating a thin service which provides the object.
I would favor the latter in most cases because it makes the code in other modules simpler. Also, in my mind, the service approach makes the code in your controllers seem less 'magic' and more debuggable, as it is clear where the library, e.g. _ comes from. Variables appearing "out of thin air" is some of the problem with global variables to begin with.
The library will still "pollute" the global scope, unless you explicitly deletes them from the global scope, perhaps after fetching a pointer to them in a service, which then can pass it on. However, I can't see any motivation for doing so. Any other attempts, such as using an Angular service to actually download the third party script and evaluating it, somehow preventing it from reaching the global scope, seems vastly inefficient, over-engineered and slow (both computationally and with regards to when HTTP requests are fired).
It's otherwise a good idea not to create any more global variables than strictly necessary.
For third party libraries that support provide a noConflict function - such as Underscore and jQuery - you could use that to prevent global pollution in your Angular factory.
myModule.factory('_', ['$window', function ($window) {
var underscore = $window._.noConflict();
return underscore;
}]);
Since all services in Angular are singletons it means that the injector uses each recipe at most once to create the object. The injector then caches the reference for all future needs.
Put third party libraries in angular constants.
Keeps your code readable and clean and you can inject them in the specific controllers, directives,... where you want to use them.
angular
.module('sampleApp', [])
.constant('_', window._)
.constant('$', window.$)
As documented in John Papa's style guide [credits to #MaximilianoBecerra]
Miike is right, you can't "stop" a module from doing badness. Once anything calls window.whatever = ...
Require.js though is cool as async module definition library/methodology which helps people who are building packages do it without mucking in the global namespace. It won't help offenders, but it's neat.
http://requirejs.org/
I've created a tool which will create an angular factory rather than a global for all libraries that support require js. Since most libraries support require.js, I was able to write a function which mimics require's 'define' function, but rather than adding the library to require, it adds it as an angular injectable. It is practically plug n' play. Just include the js source after jQuery and angular and you're good to go. It's called angular global injector and available on github. Here's the link: https://github.com/btesser/angular-global-injector
I am pretty new with AngularJS, but was wondering how to create commonly used functions outside the scope of a controller.
For example, I pretty often need to call a function to start a "Loading" spinner (for RESTful calls, etc). I tried adding a showLoadingModal() function as a service, but those only seem good for retrieving data from what I've seen. Do I have to add this function to all of my controllers, or can you create app-level functions somehow?
You could define your common method on $rootScope, which will be available via prototypical inheritance to any child scope in your application.
Or, you could certainly define a service called "utilities" and just inject it wherever it's needed. Services are good for more than wrapping data-retrieval calls!
Of these two approaches, I would recommend the latter. More testable and less pollution of $rootScope.