Does it make sense to use angular-services when we use ES6 modules? For example we need a singleton module (userService) in our code and we can do like this:
var app = angular.module('app', []);
app.service('userService', function(){
this.users = ['John', 'James', 'Jake'];
});
app.controller('FooController', ['$scope', 'userService', function($scope, userService){
console.log(userService);
}]);
But we can define the service in separate file:
/* ./user-service.js */
export default users = ['John', 'James', 'Jake'];
, then make the code like this:
var app = angular.module('app', []);
var userService = require('./user-service')
app.controller('FooController', ['$scope', function($scope){
console.log(userService);
}]);
and result will be absolutely the same as with services using. So why use angular services when we can use modules?
Yes! It makes perfect sense.
Services implement a particular responsibility in your application, moving data between the data store and views.
Modules allow you to organize your code and separate sections with different responsibilities.
By putting each service into a module, you make it easier to browse and test your code. It's easy to find all of the code that implements a responsibility.
Source: Difference between service, directive and module =)
From my own personal notes (mostly snippets from the docs, google group posts, and SO posts):
Modules
provide a way to namespace/group services, directives, filters, configuration information and initialization code
help avoid global variables
are used to configure the $injector, allowing the things defined by the module (or the whole module itself) to be injected elsewhere (Dependency Injection stuff)
Angular modules are not related to CommonJS or Require.js. As opposed to AMD or Require.js modules, Angular modules don't try to solve the problem of script load ordering or lazy script fetching. These goals are orthogonal and both module systems can live side by side and fulfill their goals (so the docs claim).
Services
are singletons, so there is only one instance of each service you define. As singletons, they are not affected by scopes, and hence can be accessed by (shared with) multiple views/controllers/directives/other services
You can (and probably should) create custom services when
two or more things need access to the same data (don't use root scope) or you just want to neatly encapsulate your data
you want to encapsulate interactions with, say, a web server (extend $resource or $http in your service)
Built-in services start with '$'.
To use a service, dependency injection is required on the dependent (e.g., on the controller, or another service, or a directive).
Directives (some of the items below say essentially the same thing, but I've found that sometimes a slightly different wording helps a lot)
are responsible for updating the DOM when the state of the model changes
extend HTML vocabulary = teach HTML new tricks. Angular comes with a built in set of directives (e.g., ng-* stuff) which are useful for building web applications but you can add your own such that HTML can be turned into a declarative Domain Specific Language (DSL). E.g., the <tabs> and <pane> elements on the Angular home page demo "Creating Components".
Non-obvious built-in directives (because they don't start with "ng"): a, form, input, script, select, textarea. Under Angular, these all do more than normal!
Directives allow you to "componentize HTML". Directives are often better than ng-include. E.g., when you start writing lots of HTML with mainly data-binding, refactor that HTML into (reusable) directives.
The Angular compiler allows you to attach behavior to any HTML element or attribute and even create new HTML elements or attributes with custom behavior. Angular calls these behavior extensions directives.
When you boil it all down, a directive is just a function which executes when the Angular compiler encounters it in the DOM.
A directive is a behavior or DOM transformation which is triggered by a presence of an attribute, an element name, a class name, or a name in a comment. Directive is a behavior which should be triggered when specific HTML constructs are encountered in the (HTML) compilation process. The directives can be placed in element names, attributes, class names, as well as comments.
Most directives are restricted to attribute only. E.g., DoubleClick only uses custom attribute directives.
see also What is an angularjs directive?
Define and group Angular things (dependency injection stuff) in modules.
Share data and wrap web server interaction in services.
Extend HTML and do DOM manipulation in directives.
And make Controllers as "thin" as possible.
Related
I inherited some code that is using a global object to to store angular services. These services get attached to the global object in the run function of the angular module. My question is, can this lead to trouble down the road? What sort of trouble does this cause for testing? Passing around services like this seems a lot easier than injecting all of the services in each controller so I see why this is done. What are other arguments for not doing this? Here is some code to illustrate what I am talking about:
// vars
var globalObject =
{
ng: {},
};
// Setup module
var myModule = angular.module("myModule", []);
myModule.config(doStuff);
myModule.run(setUpGlobals);
// Setup app globals
function setUpGlobals(ngRootScope, ngHttp, ngTimeout)
{
globalObject.rootScope = ngRootScope;
// angular services
globalObject.ng.http = ngHttp;
globalObject.ng.Timeout = ngTimeout;
}
setUpGlobals.$inject = ['$rootScope', '$http', '$timeout'];
Modules and DI were introduced in Angular exactly to avoid relying on globals and improve modularity.
This is naive approach that only works if there is a single module and a single application instance. It will fail if there are several modules that can be used separately (including tests). It will produce awful bugs if there is more than one application instance on the page (for example, if Angular is used for non-SPA applications).
A monolith module hurts testability. Even if it is used like that, some options will be unavailable, e.g. injecting spied or stubbed services in $controller(...) - because a controller relies on globals.
setUpGlobals results in eager service instantiation. This may not be a problem for core services but will be a problem for services that don't need to be instantiated right now.
Less important concern is code size in minified application. ng.$rootScope can be minified to a.$rootScope but not any further. Annotated function should mention '$rootScope' string once, but $rootScope variable name can be minified to a. There will be improvements if a service is used more than once inside a function.
There's a lot of reasons why global variables are bad. Some of them won't be applicable in this case, other ones will.
This makes testing nightmaraish. Dependency Injection is great, because it means you can do some atomic tests, by mocking out the services you don't need. In a simple, non-convulted example, imagine a service that makes API calls via http, if you DI it in, your test can mock out the http and just fake a return, letting you test only the bits of code you want, and saving you from having a test that relies on the API, or worse a test suit that uses up your API calls. With the provider in the global scope, that's much more difficult to achieve.
Just one reason, i'm sure there are many others.
Ok so I was reading here
basically when I have this
MyApp = MyApp || {};
MyApp.settings = {
isFooEnabled: false
}
if I use the rootscope and want to check if isFooEnabled I have to inject the rootScope into whatever object I want to do the check.
How does that make sense?
What is the advantage of using $rootScope.isFooEnabled over using straight standard javascript MyApp.isFooEnabled?
what is better for what?
when should I use one over the other?
The $rootScope is the top-most scope. An app can have only one $rootScope which will be shared among all the components of an app. Hence it acts like a global variable. All other $scopes are children of the $rootScope.
The rootScope's variable is set when the module initializes, and then each of the inherited scope's get their own copy which can be set independently.
NOTE:
When you use ng-model with $rootScope objects then AngularJS updates those objects under a specific $scope of a controller but not
at global level $rootScope.
The $rootScope shouldn't be used to share variables when we have things like services and factories.
Finally, Angular FAQ says this at the bottom of the page: "Conversely, don't create a service whose only purpose in life is to store and return bits of data." See from here.
Actually, I would argue that you shouldn't use $rootScope in this case, you should create a separate service (or factory) that stores your settings, however, the usage and reasons are the same.
For simply storing values, the primary reason is consistency. Modules and dependency injection are a big part of angular to ensure you write testable code, and these all use dependency injection so that unit tests can be written easily (dependencies can be mocked). Whilst there are not many obvious gains from injecting a simple object, it's consistent with the way more complex code is accessed, and there is a lot to be said for that. On a similar note, if you were to upgrade your settings object to fetch data from the server (e.g. for environment specific settings), you might want to start unit testing that functionality, which you can't really do properly without modularising it.
There is also the (frankly weak) namespacing argument - what if another library you import uses window.MyApp?
TL;DR: It's a strongly recommended best-practice. It might seem a bit clunky now, but you'll benefit from doing it in the long run.
I haven't really been fiddling for angularjs's directive for a while and I do not still have a good grasp on it. Before I dive into it, I am thinking react, on how they do their components.
So I have search on how to create reusable components using directives, and found this article:
http://michalostruszka.pl/blog/2015/01/18/angular-directives-di/
But the implementation on his final solution is quite blurry, as I cannot figure out on how to use it correctly.
Let's say I create a title directive:
<epw-title store="epwEventStore">{{vm.title}}</epw-title>
And another directive that uses the same service epwEventStore so that it can update the state
<epw-event-list store="epwEventStore"></epw-event-list>
Where the epw-event-list renders a list and when clicked should change the value of vm.title of the epw-title.
How is this possible?
Update
Q: Are they nested?
A: No, they are siblings.
Don't put Services inside Views
Just to avoid any misunderstanding, if epwEventStore is an AngularJS Service (such as provider, factory, service), it is not meant to be put as attribute value inside your template like that:
<epw-title store="epwEventStore">{{vm.title}}</epw-title>
In a well-designed decoupled architecture, your Views (template) should not "know" anything about your Services. They should only refer to controllers, directives and filters.
Different directives can use the same service
That means you can perfectly have
...
.directive("first", function(myService) {
...
})
.directive("two", function(myService) {
...
})
...
where, e.g., both directive can access and manipulate the same data.
Angular way is declarative
Following Angular's philosophy, if your directive depends on a Service, you declare it in the directive's definition. So whoever reads the code - knows immediately about all dependencies. This makes the code readable.
What the author of the article seems to be suggesting is to use events instead. Which is the publish-subscribe pattern. However, using it inside your directive, especially with $rootScope, makes the directive "leaky" as it is no more encapsulated and can both affect the external state and be affected. And worse - the reader has now manually search all your codebase for whoever is affected by the events emitted from the directive. This pattern has its uses but should be enjoyed with care.
I am just curious to know, Is it like after the removal of few components like :
The rest off other components will remain same, because it is not mentioned in the image above
like:
Services,
Event (broadcast, emit, on)
run block
constant
config
And many others.
Hope the above question is valid, If so please give me idea about what is still remains , so that I feel easier in learning/adapting the new angular 2.
TypeScript:
I have seen the changes in class oriented block changes in typescript
like :
class MyComponent {
constructor() {
this.name = 'Max'
}
sayMyName() {
console.log('My name is', this.name)
}
}
Does that mean the commonly used DOM manipulation functions like
document.getElementBy
window object
And other things will same to an extent ?
Please give me some reference or idea about How much the Typescript has changed
Question 1:
The high-level abstraction is still the same (controllers, directives, services), but all the implementation details changed as the framework is rewritten in TypeScript.
For example, angular modules will be ditched in favour of ES6 native ones, which means run block, constant and config will not be relevant. Howevver, since they're keeping dependency injection, some way of configuration must exist, so whatever you can do in config and run will still be doable.
Question 2:
You probably confused TypeScript with JavaScript. The former has always had a syntax like that (so will the next version of JavaScript (ES6/harmony) to some extent).
However, the language change does not affect how you use the framework as TypeScript is supposed to be a superset of JavaScript, so most valid JS is also valid TS. You do not have to use features specific to TypeScript if you don't want to.
Based upon my understandings of how angular 2 is coming together this is how I see the other pieces fitting together.
Disclaimers
I am not a developer on the project, just a guy who is trying to keep up with the project as it is being developed.
The current state of angular 2 is alpha/developer preview and can/will change as development progresses
Overview
As angular 1.* progressed in its maturity there was a clear movement to utilizing conventional JavaScript patterns (see controllerAs, bindToController, no global controllers) and by following that convention your code for angular 1.* will be closer aligned to angular 2. The other movement that will assist you as you prepare for angular 2 is to think about your application in the idea of components (directive + controller with services injected in).
Services
These are classes that can be injected into components
Events (broadcast/emit)
These are a pub/sub implementation based upon the inherited $scope model which is not going to be present in angular 2, so another eventing model will need implemented. I have not heard this discussed from the angular team, so either be patient or pick another pub/sub model to implement.
Run block
With angular 2 being component based when the app is run is a direct correlation with the constructor of the root component (the one being bootstrapped)
Constants
Constants in angular 1 are just values that can be injected into other components, nothing has changed here and values can be injected into components in angular 2.
Config
With the angular module system going away in lieu of ES6 modules the idea of configuration (initializing values for a service) can be done in the constructor of the service. Also, angular 2 is going to support the idea of lazy loading additional components so configuration can be done later as well as upon application start
references
angular 2 project home page https://angular.io/
ng-conf videos https://www.youtube.com/user/ngconfvideos
angular 2 todo demo https://www.youtube.com/watch?v=uD6Okha_Yj0
angular 2 forms intro https://www.youtube.com/watch?v=4C4bmDOV5hk
getting started video https://www.youtube.com/watch?v=HmWm21cCAXM
Sorry for the vague title;
I've been restructuring some of my AngularJS code, trying to be more "Angular" about it, and I've noticed this pattern popping up quite a bit:
app.service("someService", function(...) {
...
}
app.controller("ControllerForThisSection", function($scope, someService) {
$scope.someService = someService
}
Basically, the controller is mostly there to give the scope a reference to the service so a view can use it, like
<div ng-if="someService.status">
....
</div>
So I have more than a few controllers that do nothing more than depend on certain shared data or services and serve to make references to those services available through the scope.
Is there any disadvantage to using this design? Can I improve my thinking any? Is this the "angular" way to do it?
Thanks for any advice!
This is the "angular way". Shared data should be placed into services, then injected where needed.
I like to think of my Angular apps mainly in terms of models (which are usually stored in services) and views. The controllers are just the glue that allows us to project/extract the parts of our models that a particular UI view needs.
Also, think of services as returning a model API, not a model object (to quote Josh).