In AngularJS, what's the difference between $scope and the native context? - javascript

I'm just starting to look at Angular, but having a hard time wrapping my head around the need for $scope. Javascript already has a concept of scope via the context (i.e. this) and allows programmers to inject that context on a function using call or apply.
Are there any differences between Angular's, $scope, and the keyword this?
If there is a difference, then what is the value of this within a controller or directive?
Thanks in advance :)

Yes, they are not the same at all. The constructor is just an instantiated new ed constructor (the function you wrote) created by the injector.
$scope is more conceptually related to the DOM. In that elements with ng-controller get that $scope and child elements do as well. If a child element with its own scope (controller/directive) had the same properties as the parent scope You wouldn't be able to access them. It also has all of the internal information angular uses in its digest loop (dirty checking/ data binding) like watches,events,etc. I'd have a read through this
As for the myCtrl as syntax, this is nice but all it really does is put the controller instance onto the scope. With the name that you set.
eg myCtrl as foo is basically $scope.foo = myCtrlInstance;. Which you are capable of doing in your controller as well.

Related

Do all methods in Angular controllers have to be on `$scope`?

So many controllers I see have no members except for this on scope. I would imagine shared validation and business logic code never accessed directly from a binding expression need not know about the non-scope code, and only members accessed from the view actually have to be on the scope.
Could someone please clear this up for me?
That's right. Functions available to your expressions in the partials and directives should be assigned to the $scope object.
All your other logic does not have to be. If you're planning to reuse any logic between controllers it is better to extract it into a factory/service.
$scope is what binds the controller to the view; it is a special prototypical object that can be dynamically adjusted, making it very easy to quickly hook up to the view. However, using $scope directly isn't the only way to handle your controllers.
Due to the prototypical nature of $scope, and the fact that there can be multiple scopes present on a given page, it's been commonly suggested to follow the "Dot Rule" when dealing with $scope. In essence, the dot rule simply suggests that instead of assigning primitives to $scope, e.g. $scope.myString, it's always preferable to "use a dot", or, assign objects to the $scope, a la $scope.someObject.myString.
Starting with angular 1.2, a new syntax was introduced which is designed to help with this task, the ControllerAs syntax. In essence, it allows you to assign your controller (which is already an object) directly to the $scope, using a syntax like ng-controller = "someController as ctrl", and then refer to all of your bindings as properties of the controller, a la ctrl.myString. You are now automatically using the "Dot Rule", without even having to think about it.
app.controller('someController', function () {
var ctrl = this; //self reference for this
ctrl.myString = 'Some title';
});
Note that even though we are still ultimately using $scope, we don't actually need to provide $scope as a dependency on the controller, and don't need to interact with it directly. However, it is still available, should we need to use an advanced service like $broadcast.
Using the ControllerAs syntax does not eliminate $scope, because the controller is still a property of $scope, but it does allow you to break the coupling between your controller and scopes down a bit, and can make your HTML / controllers easier to read. having customerCtrl.name and companyCtrl.name is much easier to understand than having two name properties which are only really understood in context of the surrounding elements.
Unfortunately, the vast majority of documentation and tutorials still use the $scope object directly, and migration to the ControllerAs syntax has been slow. However, $scope will not exist in angular 2, and the first step to migrating from 1.x to 2.x will be to convert to the ControllerAs syntax, so if you write your code this way now, it will make it trivial to migrate.
There can be methods in controllers that are not in $scope also (May be you'll be using them as helper methods that'll be calling from $scope methods). Normally methods you wanted to call my view or variable that needed to be bind to view are kept in $scope.

When do we use $scope and when do we we use var in AngularJS?

Is it better to use var than to use $scope. in AngularJS variables inside functions?
My reason for asking this is not as simple as it seems. I recently read about $watch, $digest, $apply. Although I didn't understand it completely, I understood that $digest works in a loop.
This post explains it quite well.
How do I use $scope.$watch and $scope.$apply in AngularJS?
So if you have $scope.myVar defined in your controller, you are explicitly telling Angular to monitor the changes on myVar. Doesn't this activity slow down the overall system?
Short answer: yes, it's better to declare any variable that's purely internal to your controller as a javascript variable ("var") rather than adding it to an Angular scope.
Angular scope objects provide many nice features that allow them to act as the model in an model-view-*(MV*) architecture (for instance data binding). Or said another way, as the Angular guide to scopes says "Scope is the glue between application controller and the view".
It's best to only put objects that you need in your model, that you need bound both to the DOM and your controller/services/..., on the scope as those features do come at a performance cost, as you point out. And it can also be confusing to other's who read your code if your scopes are "cluttered" with variables that aren't actually part of your model.
Here's the specific features of scopes from Angular scope docs:
Scopes provide APIs ($watch) to observe model mutations.
Scopes provide APIs ($apply) to propagate any model changes through
the system into the view from outside of the "Angular realm"
(controllers, services, Angular event handlers).
Scopes can be nested to limit access to the properties of application
components while providing access to shared model properties. Nested
scopes are either "child scopes" or "isolate scopes". A "child scope"
(prototypically) inherits properties from its parent scope. An
"isolate scope" does not. See isolated scopes for more information.
Scopes provide context against which expressions are evaluated. For
example {{username}} expression is meaningless, unless it is evaluated
against a specific scope which defines the username property.

When is it appropriate to use a directive scope without its own controller?

My understanding is that the directives should be concerned mostly with DOM interaction and templating. Setting up the application logic related to the $scope is the responsibility of controllers instead.
Yet Angular allows you to create a scope for the directive itself, such as with { scope: true }. If you do this, when are you supposed to initialize like you would in your controller constructor -- in the post-link function? That seems like an inappropriate use of the directive, since it's not concerned with the DOM.
When it it appropriate to use an Angular directive scope instead of creating a controller that must be used with that directive instead?
Yet Angular allows you to create a scope for the directive itself,
such as with { scope: true }. If you do this, when are you supposed to
initialize like you would in your controller constructor -- in the
post-link function? That seems like an inappropriate use of the
directive, since it's not concerned with the DOM.
A directive can have its own controller, defined by the controller option. That controller has the same function as an application controller: to provide behavior for the directive. That said, I think the correct place to initialize the scope is the directive's controller, not its link function.
I think of a directive's controller as the place where you manipulate the scope and of the directive's link function as the place you manipulate the DOM. This SO question has some good insights on that matter.
When is it appropriate to use an Angular directive scope instead of
creating a controller that must be used with that directive instead?
Off the top of my head I can think of two scenarios:
You want your directive to access its parent scope, but don't want it to modify the parent scope's data. In order to do that you need to set the directive to have its own scope, i.e. scope: true.
You want your directive to be reusable. In such a case, the directive shouldn't rely on any parent scope, and should have its own isolate scope, i.e, scope: {}.
I've implemented a directive recently and used the controller function for driving its behavior and
the link function for manipulating the DOM. Perhaps you'd be interested in checking it out. Link here.

What is the role for a controller and what is the role for $scope in AngularJS?

I am an AngularJS noob but very familiar with previous MVC/MVVM frameworks. I come from an OO background but have invested a fair amount of time learning the quasi-functional nature of Javascript. Let's say that I understand closures without ever having made meaningful use of them.
I am trying to get clarity on the difference between the controller concept and the $scope concept in AngularJS.
Below I am careful when I use the '$scope' object versus referring to the concept of 'scope' in AngularJS.
In the AngularJS Conceptual Overview (http://docs.angularjs.org/guide/concepts) controllers are described as using scopes as the glue between the view and the controller. The scope seems something like a model container.
This makes sense.
What doesn't make sense is all of the examples I've seen where functions are added to the $scope object. Is the $scope object the body of the controller? If so, isn't this object inaptly named as it confuses with the 'scope' concept?
-Liking-AngularJS-But-Confused
The $scope is an object that both the view and the controllers know...
It's not actually the controller itself, but through it you can pass in references to data and methods and use them inside of the view.
The controller in angular is more like a presentation model, which holds up an object which is a "mutual friend" of both the view and the controller... that's how I like to think of it at least :)

How to bind an Angular's controller function using javascript

Is there a way in AngularJS to programmatically bind a controller method using only javascript(instead of using ng-* markup)?
Something like
$("#foo").click(FooController.foo)
PS: I don't have access to $compile
Do you really need controller's methods or scope's?
in case if you need scope's you can use angular.element('#myid').scope().method
But please keep in mind that any modification of scope's values are not detected if you do them outside of AngularJS event processing, so you need to wrap your code into $apply function of scope.
Also keep in mind that in AngularJS DOM modifications from JS are generally "big no no"
Ofcourse there are controller's functions (created using "this.xxx = function () .."). I am not sure that it is good to access them as they are kind of private, but you should be able to access same way: element(..).controller().method
It is not officially supported. For sure it is technically possible with some hacks but binding event handlers from JavaScript would mean getting access to a DOM element from a controller and it goes against principles of AngularJS.
To extend #Valentyn's answer somewhat, if you had wanted to access a controller method (and not a $scope method) -- e.g., a method defined with this in the controller constructor function (on the Angular homepage, the "tabs" directive defines function "addPane" on the controller using this) -- you can use
angular.element('#myid').controller().method()
You can, but you shouldn't. You'll likely run into trouble down the road.
If you can give a bit more explanation as to why you want to do this, there might be a better (and easier) method.

Categories