When To Use $scope vs. scope In AngularJS
When I first got into AngularJS, I started using the variable reference, "$scope," everywhere that an AngularJS scope was available. I've kept this practice up for the last two years. Then, a week or so ago, Jonathan Rowny pointed out that I was using "$scope" inappropriately in certain circumstances. As such, I'm implementing a change in my naming conventions.
Rowny pointed out that the "$" in "$scope" indicates that the scope value is being injected into the current context. But, not all references to scope are based on dependency injection. For example, in $watch, link, and cloning functions (not an exhaustive list), scope is always passed as a positional argument, regardless of its name. As such, it shouldn't be prefixed with "$".
So, going forward, my non-dependency-injection functions will go from this:
function link( $scope, element, attributes ) {
// ... with "$"
}
... to this:
function link( scope, element, attributes ) {
// ... without "$"
}
I know this might seem very nit-picky; but, I like to be mindful of the code - it makes me happy.
Want to use code from this post? Check out the license.
Reader Comments
Thanks, Ben!
I too like to be "mindful of the code" so this post interests me. I am, however, rather new to AngularJS and wondered if you could give a contextual code example of when it would be proper to use `scope` vs. `$scope`? I am just not informed well enough to understand what you mean when you say a scope reference may not be "based on dependency injection."
Thanks again,
Jim
@Jim,
No problem. When the arguments are passed-in via dependency injection, their position (in the list of arguments) doesn't matter. So, for example, I could define a Controller like this:
app.controller( "MyController", function( $scope, $timeout, $http ) { .. } );
... (scope-first) or like this:
app.controller( "MyController", function( $timeout, $http, $scope ) { .. } );
... (scope last) and it won't make a difference. This is because AngularJS doesn't care about the order of the arguments, only their names. It then uses the argument name to pull something out of the dependency-injection container and use it during invocation.
For other methods, like the link() function, that accept scope, the position is *important* and the name is irrelevant. Meaning, you could define your link function like:
function link( scope, element, attributes ) { ... }
... or like:
function link( FOO, BAR, BAZ ) { ... }
In the latter case, Foo=scope, Bar=element, Baz=attributes. This is because AngularJS doesn't care what *you* name those variables, it only cares about the position in the list (ie, Scope:0, Element:1, Attributes:2, Controller:3, Transclude:4).
Controllers, Services, Factories, and Directive functions all use dependency injection. But, off the top of my head, the following functions do *not* use DI, only positional arguments (one of which is scope).
// Linking functions (and probably other pre-link functions).
function link( scope ) { ... }
// Watch expressions (not handlers).
$scope.$on( function watchExpression( scope ) { ... }, .... )
// Transclude clone functions.
transclude( function linkClonedNode( clone, scope ) { ... } )
I hope that helps a bit.
@Ben,
Thanks, that helps! I haven't had as much need for the non DI stuff in my current experimentation so I hadn't seen a lot of what you were talking about.
I appreciate your writing on this site--I learn a lot!
@Jim,
No problem. Most of the non-DI scope usage seems to be inside of Directives; so, if you're just getting into AngularJS, and use the native directives, you'll probably be using "$scope" most of the time.
Hit me up if you have any AngularJS questions - I love it.
Hi Ben, like Jim that contextual example really helps me better understand the differences. I tend to just put $scope everywhere I need a binding to the view. Not ideal, but still early days for me.
Why is it necessary to make the differentiation?
I've always just stuck the $ on before, but does it cause a problem?
@Pete,
The only different is mindset, I suppose. A variable name is a variable name is a variable name. As such, using "$scope" everywhere won't have any negative impact on the script. For me, I just realized that using it uniformly was a symptom of my own incomplete mental model.
So, I guess it's just personal preference.
@Ben,
Thanks, this was even more informative than the post itself.
Is there any analogy for $scope and scope in Java. I am new to AngularJS, and I want to get clear ideas about the difference between them.
@Jaasir,
Do you mean "JavaScript" (instead of "Java")? Maybe I am not sure what you are asking.
@Reza,
Glad this was helpful!
I meant any kind of analogy, language is not a matter. I need some relevance with already existing thing to understand it better.
when you say scope is always passed as a positional argument, what is the main difference between $scope vs scope
does link scope refer to parent controller $scope if isolated scope is not defined.
I am using a directive to perform two way binding on user input it does not work,. is there something wrong in here
mymodule.controller("MyController", ["$scope", function ($scope){
// code here //
$scope.customer =
{
name: "Rahul",
occupation: "Web Developer",
city: "Bengaluru"
}
}]);
mymodule.directive("update", function(){
return {
restrict: 'E',
link:function(scope, elm, attr) {
scope.textValue = "AngularJS"; // this value is not updating
},
template: "<h3>Here we are using two way binding</h3>"
};
});
///////////////////HTML/////////////////////////
<div>
<p>Using custom directive value of input field should update on div when user enters</p>
<input type="text" ng-model="textValue" />
<update></update>
</div>
Appreciate your request
when you say scope is always passed as a positional argument, what is the main difference between $scope vs scope
does link scope refer to parent controller $scope if isolated scope is not defined.
I am using a directive to perform two way binding on user input it does not work,. is there something wrong in here
mymodule.controller("MyController", ["$scope", function ($scope){
// code here //
$scope.customer =
{
name: "Rahul",
occupation: "Web Developer",
city: "Bengaluru"
}
}]);
mymodule.directive("update", function(){
return {
restrict: 'E',
link:function(scope, elm, attr) {
scope.textValue = "AngularJS"; // this value is not updating
},
template: "<h3>Here we are using two way binding</h3>"
};
});
///////////////////HTML/////////////////////////
<div>
<p>Using custom directive value of input field should update on div when user enters</p>
<input type="text" ng-model="textValue" />
<update></update>
</div>
Appreciate your request