I'm really new on AngularJS and i don't know the best practices so here is my question.
What is the recommended use of parents controllers properties? Should I use different alias trough the entire webapp or there is another way to use vars and methods of a parent controller?
I'm using partials html and seems it can be confusing see userCtrl.doSomething when the partial has no declaration of userCtrl (because its declared on a partial thats includes this one).
Thanks in advance!
You should avoid to use $parent and scope variables that are not declared in your controller.
Why ? Because if you use it, your controller will be directly dependent to where you instantiated it (ng-controller). So you won't respect the MVC pattern. Your controllers should not be dependent on the View.
Your controller should not know what are his parents. Because you can do it doesn't means that you should to it.
To share data between controllers, use Services instead. That's easier and cleaner.
Related
If the right way to share data between controllers are using factory/service, what is the purpose of the $rootScope?
$rootScope exists, but it can be used for evil
Scopes in Angular form a hierarchy, prototypally inheriting from a root scope at the top of the tree. Usually this can be ignored, since most views have a controller, and therefore a scope, of their own.
Occasionally there are pieces of data that you want to make global to the whole app. For these, you can inject $rootScope and set values on it like any other scope. Since the scopes inherit from the root scope, these values will be available to the expressions attached to directives like ng-show just like values on your local $scope.
Of course, global state sucks and you should use $rootScope sparingly, like you would (hopefully) use with global variables in any language. In particular, don't use it for code, only data. If you're tempted to put a function on $rootScope, it's almost always better to put it in a service that can be injected where it's needed, and more easily tested.
Conversely, don't create a service whose only purpose in life is to store and return bits of data.
-- AngularJS FAQ
As per my understanding.
you can use $rootScope in multiple places .
global settings defined in factory and then in view you can update as per your condition. f.x layout manipulation
you can assigned $state on run.
you can handle error ($rootScope.$on(...)
I hope this will help.
Thanks
Been reading the Angular.js' Controller docs and stumbled across:
Sharing stateless or stateful code across Controllers — Use angular
services instead.
But this leaves me uncertain. How do one can share a stateless/stateful code between controllers? Or what does the "code" mean here? A model? Besides, controllers do not refer to each other, as far as I understood. Can anyone clear things out for me(others) please? Thanks.
I think what they are referring to might be one of the methods to "persist" data, sharing it between controllers or between route-changes. One way to do that is to put it in your rootScope, another is to use a service. If you define a service like this:
.factory("MyDataObject", function() {
return {};
})
Then MyDataObject will be the same object anywhere you call it, allowing you to save things into it in order to share data, functions and states between controllers (or directives, or other services, etc).
You never know with the Angular documentation, but I would guess that is what they are talking about :)
See for example this answer: Angularjs, passing scope between routes
Here is my view on subject. As angular guys have always tried to explain, scope is not your model. Angular "services" are way to do it, but word service is such and overloaded term. Coming from DDD background, I cannot reconcile word service with a state or statefulness, it just does not make sense to me. What makes more sense is ViewModel or whatever you want to call it. Since I've worked with Silverlight using MVVM pattern, I call them ViewModel. As it is a job of a "Controller" to provide Scope for a View, my controllers have been so far very lean. Bulk of logic is in a ViewModels that get associated with a View through a $scope that controller creates. Does that make sense? So my controller might take a dependency of let's say mySearchViewModel, bulk of the logic is in there and can be shared between controllers, and to associate it with a view you would do something like $scope.vm = mySearchViewModel in mySearchController.
Use case
For use in a form, I created a directive that tracks changes in an array. It allows changes to be reverted and deletions and additions to be stored separately. It allows for an array (one to many mapping in the database) to be updated incrementally (rather than requiring the server to either diff, or rewrite the entire list).
Problem?
My question is about the way I expose the functionality to the controller's scope. I currently use an two-way databound attribute on the directive's scope. This works, and it seems reliable (of course you can easily break it by reassigning the scope's value, but intentionally you can break anything).
Code
You can see this plunk to see this in action. It allows methods on the directive's controller to be called from the view and the view's controller. (I am using the directive controller intentionally because that's what I do in my actual code for the directive to directive communication, but this could also just be placed in the linking function.)
Question
Is this way of doing it bad design? Am I completely throwing AngularJS out of the window now and hacking in my own code. Are there any better ways to expose functions from a directive (keep in mind that there'll be multiple of these in a single form).
It's very easy to pass in my-attribute="someFunction()" to have the directive be a consumer of the view controller. I can't find a better way to do the opposite and have the view controller consume from the directive.
Alternative?
I've been thinking about using a service here, in which the service will provide an object that is instanciated in the view, passed to the directive, and have the directive blurp out it's results to that object. Then in turn have the view controller consume the information from that service's object. Would this be a better approach?
There's nothing wrong with your approach. In fact built-in angular directives such as ng-form use this approach to store the controller in the scope (see the name property of ng-form) http://docs.angularjs.org/api/ng.directive:ngForm
For more re-usability though I would put the api methods on the controller and then put the controller itself in the api:
this.getChanges = function () {};
this.resetChanges = function(){};
$scope.api = this;
In directives, the main purpose of the controller is to serve as an api for other directives (if you didn't need an api for other directives you could just do everything in the link function). Doing it this way ensures the api is available both on the scope as well as to any directive that 'requires' the oneToMany directive.
I just started to use AngularJS, so I'm not an expert.
I have a div that represent the right area of my html view. In that div I have a controller, i.e.
<div class="rightContainer" ng-controller="rightContainerCtrl">...</div>
Inside that div I have a table, a search region, etc. Each region inside that div has its own controllers, it looks like this:
<div class="rightContainer" ng-controller="rightContainerCtrl">
...
<div class="search" ng-controller="searchCtrl">...</div>
...
<div class="table" ng-controller="tableCtrl">...</div>
</div>
the search region for example has its own controller and it is a child of rightContainerCtrl because it needs to alter some content in the parent (rightContainerCtrl), but the rightContainer div is growing and now it's big, and contain several nested controllers.
I think that using this nested controllers it's bad in this context because all the nested controllers share the parent scope, and not all controllers needs to access all the parent scope variables, also all the controllers are "prisoners" of the rightContainerCtrl, so they are highly coupled with their parent controller.
It looks like a God object anti-pattern (God controller in this case), so I think that instead of using nested controllers I can refactor my code to eliminate the rightContainerCtrl controller and use a service instead (like in a facade design pattern), that service then will be used by the controllers instead of sharing scope variables.
but since I'm not an AngularJs expert I'm not sure if I'm right or if it's better to leave this parent controller, maybe I'm missing something, so my question is
When is better to use nested controllers (nested scopes) and when it's better to use services instead in angularjs?
Controller/scope hierarchy should not dictate how data/models are shared in an application. When you think of data sharing in Angular, think dependency injection.
In the video that is referenced in #shaunhusain's answser, Misko states that scope should refer to the model, not be the model -- so don't model/put your data into scopes. Your models/data should normally be in a service.
When writing an Angular app, first think about your models. Put them in services with APIs to get/edit/manipulate the models. Then design your views. Each view should project/use/manipulate some subset of your models. Define a controller for each view that simply glues the needed subset of the models to the view. Make your controllers as thin as possible.
(Naming a controller rightContainerCtrl is also not recommended. The controller should not know about presentation/layout.)
This is 100% judgement call, and should be based on a couple of points.
Using events creates extremely loosely coupled components, they literally do not need to be aware of one another, if you have a situation where some parent controller would alleviate the need to communicate between a bunch of controllers (via services) then it is probably a better solution.
However if you're okay with the controllers each depending on the service (not really a problem) then you could just use the service as a means of communicating changes between the controllers. I've seen tons of arguments against the singleton (of which the service is a flavor, an injected singleton, but singleton nonetheless) I find these arguments to mostly be moot and generally lack a truly elegant and concise solution. If an argument spouts on and on about how when you go from A - D you don't want to take road B but they never seem to offer road C I don't really see the point.
http://www.youtube.com/watch?v=ZhfUv0spHCY&t=30m34s
I couldn't find the exact point in the video, but somewhere at the end here he discusses the usage of controllers vs services (he also reviews bi-directional data binding which will stop you from needing to pollute the global scope so to speak).
I don't want to repeat the same code that I have in one of my controllers, so I have two options:
use $controller service inside other controller to have some kind of inheritance
use multiple ng-controller on the same element - but I don't know if this is possible?
What is the best solution to implement some kind of controllers inheritance ?
To quote Angular Docs: Controller Inheritance Example:
Controller inheritance in Angular is based on Scope inheritance.
In terms of the example in the docs, you could put your common methods on the $scope inside ChildCtrl, then those methods will automatically be available in the $scope inside BabyCtrl.
Although personally, I prefer adding common code into a service and injecting that service into multiple controllers.
There is no problem in mixing controllers. You can't use ng-controller twice in the same element though, so you would need to inject $controller or create a directive that binds to the controller.
It doesn't make much sense to inject $controller inside the main controller of the element, instead, create a directive that is bound to the componentized controller, and this way, you will have componentized a behavior. Please refer to this answer When to write a directive? to understand what I say.
Controllers are meant to control the $scope, and you don't have a way to extend the controllers. There is no problem in have multiple controllers changing a single scope and using it as a medium of communication between them.
Only use a service if you have a repetitive operation that you do not need a scope necessarily, just like fetching data, manipulating objects, calculating and etc.
You could also consider isolating the common functionality into a service.