4

I'm trying to follow best practise but have a problem understanding when to use $scope and when to use 'this'. I have a simple example using angularjs 1.4.8.

<!DOCTYPE html>
<html ng-app="testApp">
<head>
<title>Test button action</title>
<script src="./angular.min.js"></script>
<script src="./testBtn.js"></script>
</head>
<body>
    <div ng-controller="TestCtrl as test">
        <button ng-click="testBtn()">test button</button>
        {{testResult}}
    </div>
    <div ng-controller="Test1Ctrl as test1">
        <select ng-model="chosen" ng-change="getDetails(chosen)">
            <option value='option1'>Option1</option>
            <option value='option2'>Option2</option>
            <option value='option3'>Option3</option>
        </select>
        <p>You choose {{test1Result}}</p>
    </div>
</body>
</html>

The testBtn.js file looks like this

(function() {
    'use strict';
    angular.module("testApp", []);
    angular.module("testApp").controller("TestCtrl", testCtrl);
    angular.module("testApp").controller("Test1Ctrl", test1Ctrl);
    function testCtrl($scope) {
        $scope.testBtn = testBtn;
        function testBtn() {
            if (this.testResult == '' || this.testResult == null) {
                this.testResult = "Button clicked";
            } else {
                this.testResult = '';
            }
        }
    }
    function test1Ctrl($scope) {
        $scope.getDetails = getDetails;
        function getDetails(opt) {
            this.test1Result = opt;
        }
    }
})();

This works fine as it stands. However if I change the two functions to say this.testBtn = testBtn; and this.getDetails = getDetails; clicking the button or choosing an option doesn't work and no errors are shown in the console log.

Why doesn't 'this' work in these examples? Would there have been a better way to do this?

4 Answers 4

3

When you use ng-click="testBtn()", angular will by default go and look for testBtn function in $scope object of the controller. Therefore, if you have not defined above function as $scope.testbtn = function()..., angular will not do any operation as function is not defined.

In as syntax of controller, function/models are defined using this scope of the controller. Best practice for using this is to store it at the first line of controller in a variable so that you wont fall into any scope conflicts.

angular.module("testApp").controller("Test1Ctrl", test1Ctrl);
    function testCtrl($scope) {
        var ctrlScope = this;
        ctrlScope.testBtn = function() {
            if (ctrlScope.testResult == '' || ctrlScope.testResult == null) {
                ctrlScope.testResult = "Button clicked";
            } else {
                ctrlScope.testResult = '';
            }
        }
    }

<div ng-controller="TestCtrl as test">
    <button ng-click="test.testBtn()">test button</button>
    {{test.testResult}}
</div>

"as" syntax makes the code more readable in my opinion and also take care of name conflicts if controllers are nested.

Sign up to request clarification or add additional context in comments.

1 Comment

Many thanks for the explanation. I've now been able to eliminate $scope from my code.
1

You need to use test and test1 controllerAs in view as well. Then you must use this in controller. Advantage: Nested controllers with same model names.

<div ng-controller="TestCtrl as test">
    <button ng-click="test.testBtn()">test button</button>
    {{test.testResult}}
</div>
<div ng-controller="Test1Ctrl as test1">
    <select ng-model="test1.chosen" ng-change="test1.getDetails(test1.chosen)">
        <option value='option1'>Option1</option>
        <option value='option2'>Option2</option>
        <option value='option3'>Option3</option>
    </select>
    <p>You choose {{test1.test1Result}}</p>
</div>

$scope is used when your controller is bind to a route like ng-route module or state like ui-router.

1 Comment

"$scope is used when your controller is bind to a route like ng-route module or state like ui-router." Why can't I use $scope without ng-route or state? Why was the edit made that I must use 'this' keyword with controllerAs sytax?
0

I am using vm for controllerAs variable.

John Papa has a great publication about it and for me and my team it became something like a good practice.

AngularJS's Controller As and the vm Variable

The main advantages:

  1. Provides a consistent and readable method of creating bindings in my controllers
  2. Removes any issues of dealing with this scoping or binding (i.e. closures in nested functions)
  3. Removes $scope from the controller unless I explicitly need it for something else
  4. Makes me happy since its short :)

Comments

0

this in javascript is very generic and it is referring to self-refrence for current object, but in AngularJs to share anything between controller and html you have to share it thru $scope, actually your code is registering "testBtn" first in $scope.testBtn = testBtn; then implementation in function testBtn() to understand it let me rewrite it here :

$scope.testBtn = this.testBtn;
this.testBtn = function() {}

javascript languge will not face any ordering problems, and will understand it as:

this.testBtn = function() {}
$scope.testBtn = this.testBtn;

inside your function this will refer to object that you function inside which is $scope so anything inside $scope you can access by this inside function only as it is registered in $scope already.

my recommendation for you to use $scope and don't use this to not be confused, also no need for registering then implementation you can do it in one step, it is confusing, here I'm rewriting your controller:

function testCtrl($scope) {
    $scope.testBtn = function () {
        if ($scope.testResult == '' || $scope.testResult == null) {
            $scope.testResult = "Button clicked";
        } else {
            $scope.testResult = '';
        }
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.