$scope vs. scope

John Lindquist
InstructorJohn Lindquist
Share this video with your friends

Social Share Links

Send Tweet
Published 11 years ago
Updated 6 years ago

This episode is explaining the naming conventions behind for the arguments passed to the factory functions for controllers, directives, linking functions, etc., its implications in regard to Angular’s dependency injection, minification side effects on arguments, and how to prevent them.

John Lindquist: Let's talk about the difference between this $scope, with the little dollar sign right there, and this scope which is in a linking function, which doesn't have a dollar sign.

If you look at our HTML you can see that we have a controller and then a directive inside of it, and if we log this out, you can see I'm doing console.log on both that, and that scope, you can see that it's the exact same scope, same id and everything. It's just the exact same thing.

As we've mentioned before, if you isolate it by giving it its own scope, then it will create a new scope for that, so you can see four and three, so they're different.

That's not really the topic we're going to go into here, we're actually going to discuss why these are different, why they are named differently.

We'll start right here. You've probably seen scope, element, attributes, and you've always seen them in that order. If I were to log out the element, I'll comment this out.

If I were to log out the element, you can see it's logging out the element for obvious reasons. If I change the order of these, so that element comes first and scope comes second, you can see that we're back to getting the scope. That means that this is not the element, this is the scope, because the order here is important.

It doesn't matter what I name this, I could name this whatever, APU, and I refresh, and I still get that scope. I could even name it $scope, even though this kind of goes against convention. But that's still going to give us the scope because the naming does not matter. What matters here is the order.

The reason being is that this is just a method that's being called with those specific things as the arguments, with the scope, element, no matter what these are named, even though it's $scope, scope, attributes, or scope, element, attributes. It doesn't matter what you name them.

This is completely different, and with good reasons, from what's going on up here. Let's comment this out. If I pass in the scope, I'll just make sure it's working, so you've got the same scope. If I pass in the $scope, and I change the name of this to just $scop and I try to log out $scop you'll see that we get an error instead, because there's no such thing as a $scopProvider. That's because these guys that are passed into things like a controller, or a service, those are all dependent on the providers that are available.

There are things like an $httpProvider, a $parseProvider and other things that have been predefined. If I log $http here, you can see that it's going to show me exactly what that $http function is. If I change the order, and I put $http first, and I put $scope second, I'm still going to get $http. The order does not matter. What matters here is the name, because what it's doing is, it's taking the name of whatever you pass in, and then trying to find a provider for this. This is using dependency injection to do a lookup based on the name, to find a provider to satisfy its dependencies.

If you look at this a little bit differently, this is actually kind of a shorthand that the longer version of what's going on here -- I'm just going to delete all of this -- the longer version of what's going on here is that we can pass in an array as a second value here. We can set up the dependency injection in this way, by saying we want the scope there, and then the last value in the array can be the function. Then I can name the scope whatever I want, so I'll just name it scope for now. I'll do console.log($scope), and then I get the scope again when I log it out.

Because I did it this way instead, and you can do things like the service and the factory, and other guys, in this exact same way. If I do it this way instead, this is what's going to protect against minification. When you minify things, it will rename things like "scope" to "a". If I call this "a" I'm still going to get the scope, because I'm looking up by name using a string here, and the string is not going to get minified. It's looking up the scope provider and then passing it as the first argument.

This is kind of a longhand way of doing it, but it's what protects against minification when you run it through the minifiers that are out there.

It's much more convenient through the shorthand way¸ and there are tools being built to help generate this longhand way for you. But for right now, if you are worried by minification, it's pretty well covered in the docs. But just to kind of show what else is going on here I will pass in $http, and then just call this "b." If I log out a, I still get the scope, if I log out b I'll get http. If I'll change the order, I'll get the scope again. Now the order is important because I defined the order here.

This may be a little bit confusing if you're not used to the concept of dependency injection, of looking up providers using an injector to satisfy dependencies. Because what's going on, it's looking up what it needs to fulfill this, and then passing it in. It has absolutely nothing to do with how this is being called, where it's simply calling a method and then passing in arguments one, two and three.

This is a completely separate process of looking up dependencies, and then passing them in based on the name. Hopefully that clears it up a little bit. While some people may think that it's inconsistent, it's actually, if you look at how this is done here, if you want to inject something into your directive, you can similarly say $http here, or $parse or some of the other providers.

Actually, if I look the AngularJS source, and you just search for $provide.provider you can see a list of the things that you can inject that are provided by AngularJS itself. $log, $parse, $route, $rootScope, $q, $sniffer, things like that, or some of the services you define yourself. You can inject those as well, and those have nothing to do with this link function.

This link function is just the scope that's available for the component you're working on. The element which is the element, the tag and attributes that you're working on inside of your directive, which is completely separate from the providers used in AngularJS for things like filtering and interpolating and making HTTP requests.

Hopefully, that clarifies a bit what's going on. How these are completely different, and why the naming is important here. They use a dollar sign just to say this is an Angular thing. If you look in here, they're all prefixed with dollar signs. Then, in here they're Angular things that are injected, and then in here the naming doesn't really matter, it's just scope, element, attributes because that's the best name for those things.

That's $scope vs. scope. Hopefully that clears it up. You can use apps, service, and use the same syntax for finding the name and then injecting things at factory, or in a lot of the other things, or in configuring your module. Then this always has to be the same, you can't change in what order these are.

Anyway, I've repeated that enough times, so hopefully that will stick, and good luck.