Angular JS working - javascript

I just started learning about Angular JS. Though I can code up an Angular module, I have lot of questions on how Angular works.
How does $scope work? I understand that one root scope is created at the point of declaration of ng-module. This represents the DOM in some way and also watches the DOM for any changes in properties, events, etc.. How does this watch implemented?
How is it ensured that this scope object is ready once the page loads, so that it can be used by the controller? How does access permissions work with the scope object, cases where controller might not have access to a variable?
In which cases you might want to use an injector explicitly?
What's lifecycle of an angular app in detail? Is there any client side versus server side component or is it entirely client side? When I say, ng-repeat, this is still client side?

$scope is what angular uses to expose variables to the template. Think of scope as your 'view model'. Anything attached to the scope will be exposed. $scope uses prototyped inheritance. This means that children of a scope will have access to the parents properties. There are more detailed nuances to scope inheritance involving change detection.
Dependency injection solves the 'ready' problem. Angular takes care of injecting the scope properly in each controller already instantiated.
If you need to create a function that modifies a service when that service hasnt been instantiated yet. For example configuring an error handler. Only providers will be available, using the injector we can grab the service when the error is thrown.
`
function(rejection) {
if (rejection.status === 401) {
// have to lazy inject cause http interceptors are defined
// at provider configuration
var sessions = $injector.get('sessions');
var $state = $injector.get('$state');
sessions.logout().then(function() {
$state.go('login');
return $q.reject(rejection);
});
}
}
return $q.reject(rejection);
}
I recommend reading this documentation to shed some light on 'the angular way'. https://docs.angularjs.org/guide/scope

Related

Angular Project Architecture

I am building an app in angular, which consumes different APIs and Gives options for the user to select it will be recorded and sent back to the server.
I have designed it as follows.
All the common logic in Main Controller and all other options in different controllers as the child of main controller.
Main Controller retrieve all the data that are required to run the app.
which is consumed by all other child controllers.
To make sure data is loaded I am using promise attached to scope. So all the child controller will know data loaded.
I have moved data updation part of all child controllers to main controller
because all the updates happen in one object.
Child Controller emit/broadcast to communicate between child and main. So when update happens child will emit an event with data which will be captured by Main and it will do the update.
MainController {
$scope.loaded = DataService.get();
$scope.userOptions = {};
$scope.$on('update',function(){
updateUserOptions();
})
}
ChildController {
$scope.loaded.then(function(){
//all logic of child controller
}
$scope.onselect = function(){
$scope.$emit('update',data);
}
}
Questions
Is it a good practice to use events between controllers ?
is it good to use promise attached to scope for child controllers ?
Will it improve my code if I start using services ?
I will try to answer your question based on my own experience. Recently I've built a single page application and I've refactored its architecture.
Here are my answers:
Is it a good practice to use events between controllers? IMHO, it is the most flexible way to share information between all controllers even if they have isolated scope (using $broadcast or $emit for example). This is called the Observer design pattern. However, you can use services instead of events to share data between them. If you are going to use $rootScope, be careful as all the $scopes inherit from $rootScope.
is it good to use promise attached to scope for child controllers ? Firstly, you have to learn about how scope inheritance works. You have to take care to avoid property shadow in JS. Secondly, I would move out all the logic from scope.loaded in ChildController to a service such as ChildService. Keeping the business logic (such as request, etc) in Services instead of Controllers, will ensure it can be re-used.
Segregation of business logic is good design principle.
Will it improve my code if I start using services ? I answered this question above.
In addition, in order to build a good architecture I've read this angular style guide written by John Papa.
I recommend the following changes:
To make sure data is loaded I am using promise attached to scope. So all the child controller will know data loaded.. Instead I would emit a custom 'loaded' event in the MainController using $scope.$emit('loaded'). After that, in the ChildController I would use $scope.$on('loaded', function(){}) to handle the event.
I would move the updateUserOptions function to a service and inject the it into just the controllers that need it.
I hope that helps!
Is it a good practice to use events between controllers ? Not as the main form of data sharing, but you can use it to notify about system events, such as data ready.
Is it good to use promise attached to scope for child controllers ? Don't use scope inheritance, it causes lots of annoying problems.
Will it improve my code if I start using services ? Yep.
This is what I would do in your place:
dataService - this service is responsible for all data coming in / going out. Whenever a request for data is made (no matter which controller asked for the data), the service caches the data (save the promise is good enough). All further requests get the cached data unless they specify they want a fresh data. Whenever data is updated (1st time or refresh), the service broadcasts a 'dataReady' event via $rootScope to which the main controller and other subscribers can listen.
The service is also responsible for data updates, and when the data is updated you can also broadcast an event via the $rootScope.
When the event is activated, all subscribers query the service, and get the data they need.
Controllers - avoid controllers, use directives with isolated scope, and pass the data between them using attributes. In this way you can be sure that each directive gets what it needs, and not everything. The directives can communicate using attributes, services, broadcast / emit or require their parents / siblings if they work closely together.
Is it a good practice to use events between controllers ?
No it's not, it will be deprecated by Angular JS 2.0. It also often leads to unmanagable tangle of events which are hard to understand and debug. Use services to share data between controllers. (Inject same service into multiple controllers, service then holds data, controllers bind to that data and are automatically synchronized) I wrote a blog post explaining this use case.
Is it good to use promise attached to scope for child controllers ?
No it's not. Use promises and resolve data in services. Don't use $scope at all but use controllerAs syntax instead. $scope was deprecated also in Angular JS 1.X because it's usage leads to many different problems with scope inheritance.
Will it improve my code if I start using services ?
YES! Use services for all logic and data manipulation. Use controllers only for UI interaction and delegate everything to services. Also use ui-router for managing state of your application.
I'm not going to answer your questions directly as I have some other comments as well. I think the approach you mentioned is not the best way to build angular applications.
All the common logic in Main Controller and all other options in different controllers as the child of main controller.
It's against all angular style guides to place common logic in controllers. Controllers should only be used for the logic related to the view (data binding, validation, ...). Because the code inside a controller is not reusable, the less code you have in a controller the better. The more logic you have in services, the more scalable your application becomes.
Fix: I suggest you create a service that retrieves data from the server, and inject this service in controllers as you need. Notice also this way offers better dependency management as you can keep track of which controllers need which services exactly.
Nested controllers should be avoided when possible, because angular keeps track of all the active scopes and re-evaluates them in every $apply() loop.
Fix: same as #1, use services instead of the main controller.
To make sure data is loaded I am using promise attached to scope. So all the child controller will know data loaded.
Using a promise for data retrieval is a good practice. But, again, keeping it in a service is much cleaner than main controller.
I have moved data updation part of all child controllers to main controller because all the updates happen in one object.
Child Controller emit/broadcast to communicate between child and main. So when update happens child will emit an event with data which will be captured by Main and it will do the update.
Fix: use a service with an update function instead of events. Events are harder to debug and track. And you need to unregister event handlers on destroying a controller. If you can use a function/promise instead of events, then it's usually a better idea.
Is it a good practice to use events between controllers ?
A problem with your current set-up is that you're implicitly relying on the hierarchy of your controllers (the fact that one is the child of the other) - because you emit the event, only scopes higher up on the hierarchy can catch it. Besides being an implicit connection (that a developer has to remember), this also limits he extendability of this feature.
On the other hand, if you injected a shared service into all the controllers that need it, the connection between the controllers would become explicit and documented, and their scopes' position in the hierarchy independent. This will make your architecture easier to maintain, with the added benefit of also being easier to test, for one.
You can still implement an observer pattern with a service.
is it good to use promise attached to scope for child controllers ?
The issue of polluting scopes pointed out in other answers is valid. This is one of the reasons why it's better to limit the number of objects you attach to your scope, and to use objects as bundles of variables on your scope instead of attaching all the variables to the scope directly.
(For an explanation of these reasons, see discussions about "always having a . in your bindings".)
(Of course, don't do this blindly just to reduce the number of variables, try to find semantic connections between variables that might be bundled together sensefully.)
Will it improve my code if I start using services ?
I think the above answers already outline the answer for this: yes. There are other benefits too, but this format is not best for too long answers, so I won't list anything else now.
All in all, these above pointers are not big issues with your code currently, but if you're looking for the best architecture, I think you can do better.
Answers:
No, it will be deprecated soon.
$scope is deprecated already.
Services is a great choice. Services allow us to share data and behaviour across other objects like controllers.

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.

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.

Associating Controllers with Angular Scope Objects explicitly

From the AngularJS documentation Understanding controllers:
Associating Controllers with Angular Scope Objects
You can associate Controllers with scope objects implicitly via the
ngController directive or $route service.
Those two approaches are well known and mainly used across AngurlaJS applications.
What draw my attention is this part found in Developer Guide / Understanding the Controller Component:
Associating Controllers with Angular Scope Objects
You can associate controllers with scope objects explicitly via the
scope.$new api or implicitly via the ngController directive or $route
service.
So in addition to implicit association of Controller with scope there is mentioned also explicit way by using scope.$new api.
I am aware that scope.$new is used to create new [isolated] scope but I somehow don't understand how exactly is it related to explicit association of controller with scope.
It would be great to see some practical use case and/or more detailed explanation.
It's primarily used during testing when you want to construct a controller directly and do something with it.
You can use the $controller service to do this:
var scope = $rootScope.$new();
var ctrl = $controller(MyAwesomeController, { $scope: scope });
Now I can manipulate the scope variable directly and check for side effects:
scope.foo = 'bar'
scope.$digest();
expect(scope.bar).toBe('YEAH BABY!!!');
The $controller service will instantiate a controller with all of the dependencies injected like you would expect. It also allows you to pass in a hash of locals that will override any of the dependencies with something you provide explicitly.
Again, this is very useful for testing because you can swap out a service with a mock if needed.

$rootScope vs. service - Angular JS

What is the difference between implementing a $rootScope function and a service? Security wise or performance wise.
I have read this, so I am wondering.
I have been trying to figure out whether or not a certain global function for my app would be best implemented in a service or on the $rootScope itself. To pitch you guys with an idea of what I am making, I'm currently developing a dirty form function in which it prompts the user if he/she navigates away from a certain form. In this case, I decided to best implement it as a global function, so any hints?
Thanks for the responses,
Jan
In this case I would go for a service to avoid having a global state. all new scopes are created from $rootScope. New controllers or whoever uses a scope will have values of $rootscope available. For instance, if you define $rootScope.validate() and in a controller you define a function $scope.validate() because you forget about the first definition, something will certainly go wrong.
There is an article by Misko H. about this http://misko.hevery.com/code-reviewers-guide/flaw-brittle-global-state-singletons/
Services are instantianted on demand, whereas $rootScope is created during bootstrap, and can be injected wherever you need them. This is good for testability.
Angular won't instantiate services unless they are requested directly or indirectly by the application.
(http://docs.angularjs.org/guide/dev_guide.services.creating_services)
As #egamonal mentioned Services are more robust way to share common functionality. Not only services are instantiated on demand, they are singleton by nature so once a service gets created, the same instance gets passed around by AngularJS whenever requested. So if something can go on root scope, it can also be implemented using a service.
One think to keep in mind using such global approach is the possibility on memory leak. Instance of JS classes or maybe DOM elements remain in the memory because you have referenced them from you global functions (either in $rootscope or service).

Categories