Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <blockquote> <p>"How does <code>this</code> and <code>$scope</code> work in AngularJS controllers?"</p> </blockquote> <p><strong>Short answer</strong>:</p> <ul> <li><code>this</code> <ul> <li>When the controller constructor function is called, <code>this</code> is the controller.</li> <li>When a function defined on a <code>$scope</code> object is called, <code>this</code> is the "scope in effect when the function was called". This may (or may not!) be the <code>$scope</code> that the function is defined on. So, inside the function, <code>this</code> and <code>$scope</code> may <strong>not</strong> be the same.</li> </ul></li> <li><code>$scope</code> <ul> <li>Every controller has an associated <code>$scope</code> object.</li> <li>A controller (constructor) function is responsible for setting model properties and functions/behaviour on its associated <code>$scope</code>.</li> <li>Only methods defined on this <code>$scope</code> object (and parent scope objects, if prototypical inheritance is in play) are accessible from the HTML/view. E.g., from <code>ng-click</code>, filters, etc.</li> </ul></li> </ul> <p><strong>Long answer</strong>:</p> <p>A controller function is a JavaScript constructor function. When the constructor function executes (e.g., when a view loads), <code>this</code> (i.e., the "function context") is set to the controller object. So in the "tabs" controller constructor function, when the addPane function is created</p> <pre><code>this.addPane = function(pane) { ... } </code></pre> <p>it is created on the controller object, not on $scope. Views cannot see the addPane function -- they only have access to functions defined on $scope. In other words, in the HTML, this won't work:</p> <pre><code>&lt;a ng-click="addPane(newPane)"&gt;won't work&lt;/a&gt; </code></pre> <p>After the "tabs" controller constructor function executes, we have the following:</p> <p><img src="https://i.stack.imgur.com/PUMuU.png" alt="after tabs controller constructor function"></p> <p>The dashed black line indicates prototypal inheritance -- an isolate scope prototypically inherits from <a href="http://docs.angularjs.org/api/ng.$rootScope.Scope">Scope</a>. (It does not prototypically inherit from the scope in effect where the directive was encountered in the HTML.)</p> <p>Now, the pane directive's link function wants to communicate with the tabs directive (which really means it needs to affect the tabs isolate $scope in some way). Events could be used, but another mechanism is to have the pane directive <code>require</code> the tabs controller. (There appears to be no mechanism for the pane directive to <code>require</code> the tabs $scope.)</p> <p>So, this begs the question: if we only have access to the tabs controller, how do we get access to the tabs isolate $scope (which is what we really want)?</p> <p>Well, the red dotted line is the answer. The addPane() function's "scope" (I'm referring to JavaScript's function scope/closures here) gives the function access to the tabs isolate $scope. I.e., addPane() has access to the "tabs IsolateScope" in the diagram above because of a closure that was created when addPane() was defined. (If we instead defined addPane() on the tabs $scope object, the pane directive would not have access to this function, and hence it would have no way to communicate with the tabs $scope.)</p> <p>To answer the other part of your question: <code>how does $scope work in controllers?</code>:</p> <p>Within functions defined on $scope, <code>this</code> is set to "the $scope in effect where/when the function was called". Suppose we have the following HTML:</p> <pre><code>&lt;div ng-controller="ParentCtrl"&gt; &lt;a ng-click="logThisAndScope()"&gt;log "this" and $scope&lt;/a&gt; - parent scope &lt;div ng-controller="ChildCtrl"&gt; &lt;a ng-click="logThisAndScope()"&gt;log "this" and $scope&lt;/a&gt; - child scope &lt;/div&gt; &lt;/div&gt; </code></pre> <p>And the <code>ParentCtrl</code> (Solely) has</p> <pre><code>$scope.logThisAndScope = function() { console.log(this, $scope) } </code></pre> <p>Clicking the first link will show that <code>this</code> and <code>$scope</code> are the same, since "<em>the scope in effect when the function was called</em>" is the scope associated with the <code>ParentCtrl</code>.</p> <p>Clicking the second link will reveal <code>this</code> and <code>$scope</code> are <strong>not</strong> the same, since "<em>the scope in effect when the function was called</em>" is the scope associated with the <code>ChildCtrl</code>. So here, <code>this</code> is set to <code>ChildCtrl</code>'s <code>$scope</code>. Inside the method, <code>$scope</code> is still the <code>ParentCtrl</code>'s $scope.</p> <p><a href="http://jsfiddle.net/mrajcok/sbZw7/">Fiddle</a></p> <p>I try to not use <code>this</code> inside of a function defined on $scope, as it becomes confusing which $scope is being affected, especially considering that ng-repeat, ng-include, ng-switch, and directives can all create their own child scopes.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload