Is it ok to use $controller inside a controller? - angularjs

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.

Related

When to use $rootScope on Angularjs?

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

what is the use of $scope in Angular js? Is $scope and this (controller context) can be used interchangably .. [duplicate]

This question already has answers here:
'this' vs $scope in AngularJS controllers
(7 answers)
Closed 7 years ago.
I can access controller variable on markup by using controller alias dot(.) variable name, so why we need $scope separately.. can we use the controller context and $scope interchangeably .. or there is some thing specific for which $scope is designed.
This is a good question, but perhaps too broad to get single clear answer. I'll offer my thoughts.
$scope was designed to be the view's model - the "VM" in MVVM pattern.
controller-as was introduced to follow an MVC pattern more closely where $scope inheritance is overkill and unnecessary. The "C" corresponds to an Angular controller, and allows the view to trigger a controller action directly.
I think the introduction of controller-as was a nice change. But I believe the right way to use it is for calling methods that is under the immediate control of the controller. In my opinion, I think that methods in controller scope should not propagate up the $scope stack, and call another method higher up the $scope chain. Doing so introduces complex dependencies, which is hard to understand and maintain. Controller-as prevents that.
Although controller-as can be used for storing models (not just for calling methods), I don't believe that it should. That is the job of the view model or $scope. I know others might feel differently.
$scope is not a singleton service. Meaning, when we inject it somewhere, usually it will create a new child scope. So, using $scope, we can propagate events for all its parents/children.
Also, we can store some "global" variables methods in parent scope.
If you use controller-as syntax, you are not able to work with this nesting. But code becomes more predictible.

Correct use of parents scope properties

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.

When to use $scope directly?

I just started out with Angular and have been reading through a lot of Tutorials.
Now the free one at CodeSchool which was my starting point doesn't mention $scope at all.
From what I've gathered, the controllerAs syntax is relatively new (1.2.0) but it seems to allow you to get away without using $scope directly.
Some articles say "use controllerAs" with an explanation, but most just use $scope. But I couldn't find any explanation why they'd choose it.
Is this now mainly a case of favoring one over the other or are there still reasons to use $scope?
Even many new directive plugins use it instead of allowing you to bind it to a particular controller.
edit: To clarify, I want to know when to use $scope, not the reasons not to use it :)
In the Angular documentation for ngController it explains the advantages to using 'controller as' vs. injecting $scope. Here's what it says:
Using controller as makes it obvious which controller you are accessing in the template when multiple controllers apply to an element.
If you are writing your controllers as classes you have easier access to the properties and methods, which will appear on the scope, from inside the controller code.
Since there is always a . in the bindings, you don't have to worry about prototypal inheritance masking primitives.
For my own part I've found using 'controller as' quite beneficial as it forces me to consider whether code I'm adding to a controller would be more appropriately added into a service or directive.
For example: watches. Watches are something you should avoid in controllers but having easy access to $scope allows you to set them up easily. Using 'controller as' has forced me to think more carefully about whether I really need to do a watch. Usually a watch can be accomplished with a directive. This has led me to create smaller controllers that only set up an initial state and communicate with services, a pattern I've found much more performant and maintainable.
The best answer I can give you is this:
The short:
Whenever you want to expose logic to the template, use Scope.
Whenever you want to persist logic to an element, use ngController.
If you want to expose your controller's values directly in the template (through the scope), use the "controller as syntax".
The long:
An Explanation
Scope or $scope, as you've put it, is where we maintain values (no matter the type: Function, Object, String, etc.) that may be available to the template within that scope. For example, consider the following:
The HTML:
<div ng-controller="MyCtrl">
<div>{{ message }}</div>
</div>
<div ng-controller="MyCtrl as ctrl">
<div>{{ ctrl.message }}</div>
</div>
See those interpolations? Well, guess what? They're both accessing Scope. The "controller as syntax" creates an alias for MyCtrl and publishes it on the local scope. Once the element has been linked, if you look at $scope you will actually find a property ctrl that exposes the controller.
The Javascript
function MyCtrl($scope) {
$scope.message = "controller MyCtrl";
this.message = "controller as syntax";
}
Where ever I use MyCtrl these two messages are available. But to readily access a value on the controller itself we use the "controller as alias" syntax.
They are honestly two different methodologies. The controller as * syntax allows the developer to put the controller onto the scope and more easily access said controller. So, in the end it all ends up on the scope. Otherwise, say through a directive's link function, you have to access the controller the require property. The controller's methods and properties don't necessarily need to be exposed to the template, rather just used in the logic. (In addition, you can access a controller through a jqLite's data() function as well).
Sometimes when propagating a controller to multiple elements we want something that is available by default to every element that uses this controller. This is particularly valuable when creating directives. Take a look at ngModel and see how we have multiple methods common to every element that uses ngModel.
Scope vs. Controller
The major thing to consider is that a child controller can inherit the scope of it's parent. The cool thing is that the child scope will inherit that bit of parental controller properties from the parent.
<!-- ctrl1 -->
<div ng-controller="MyCtrl as ctrl1">
<div>{{ ctrl1.message }}</div>
<!-- ctrl2 -->
<div ng-controller="MyCtrl as ctrl2">
<div>{{ ctrl2.message }}</div>
</div>
</div>
Notice that both are using the same controller but they have different aliases. Now, the controller properties are being passed down to the children through Scope. So the child can access the parent through it's alias. So, through this syntax you can clearly see the separation of the two instances of MyCtrl. They both have a message property on their scopes, but they are easily distinguished without digging through parents, children, siblings, etc.
In Conclusion
If you want to expose values to the template use scope. If you want to bind values to an element that don't necessarily need to be exposed in the template, use the controller. If you need to access values from your controller in your template, use the controller as syntax. Using the controller as * syntax places the controller's values on the scope under the alias created in the syntax. So, in that case, you are using both the controller and the scope together.
As stated in the Angular documentation the benefits are
Using controller as makes it obvious which controller you are
accessing in the template when multiple controllers apply to an
element.
If you are writing your controllers as classes you have easier access to the properties and methods, which will appear on the scope,
from inside the controller code.
Since there is always a . in the bindings, you don't have to worry about prototypal inheritance masking primitives.
I really like it since it makes it easy to differentiate between which controller I am currently accessing.
I read a few blogs and came to a conclusion for usage purpose do not mix $scope and this.
There is a reason for that , "this" and $scope can be different they are not always the same for example-
If I have defined a controller on "this" and I call another controller in it then the $scope will be set to the controller I called but "this" will always be the current context that is the controller in which I called the other controller.
So in this case $scope and "this" will not be same and using them interchangeably here may lead to some unexprcted behaviour.
Please correct me If I am wrong.

How to output data from a directive to a controller, and should I?

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.

Resources