3

While reading about Angular data-binding - came across advice -

"Due to the nature of JavaScript itself and how it passes by value vs. reference, it’s considered a best-practice in Angular to bind references in the views by an attribute on an object, rather than the raw object itself."

source: ng-book

Question: 1. What does it mean - binding references rather than objects?

This is accompanied by code snippet.

JS Code:

var module = angular.module("app", []);
//controller uses $timeout
module.controller("MyController", function ($scope, $timeout) {
    var updateClock = function () {
        $scope.clock = {};
        $scope.clock.now = new Date();
        $timeout(function () {
            $scope.clock.now = new Date();
            updateClock();
        }, 1000);
    };
    updateClock();
})

HTML:

<body data-ng-app="app">
<div data-ng-controller="MyController">
    <h5>Hello {{clock.now}}</h5>
</div>
</body>

Question: 2. If I remove this line $scope.clock.now = new Date(); from outside the $timeout - it does not work. Although clock.now is being assigned date object in $timeout. Why?

2 Answers 2

1

Q1:

  • it has some stuff to do with readability and this and scope context
  • {{this.now}} vs {{clock.now}}
  • the data binding on the scope might not trigger a digest cycle
  • but even then using $scope doesn't resolve debugging issues, and readability entirely

Q2:

Here are three examples, I prefer the syntax of Controller1 it makes debugging easier imo:

var module = angular.module("app", []);
module.controller("Controller1", function ($timeout) {
        var vm = this
        vm.clock = {now: 'its loading'};
        vm.now = new Date();
        var updateClock = function () {
            $timeout(function () {
                vm.clock.now = new Date();
                updateClock();
            }, 3000);
        };
        updateClock();
    })

module.controller("Controller2", function ($scope, $timeout) {
        $scope.clock = {now: 'its loading'};
        $scope.now = new Date();
        var updateClock = function () {
            $timeout(function () {
                $scope.clock.now = new Date();
                updateClock();
            }, 3000);
        };
        updateClock();
    })

module.controller("Controller3", function ($timeout) {
        var vm = this
        var updateClock = function () {
            $timeout(function () {
                try {
                  vm.clock.now = new Date();
                } catch(e){
                  vm.clock = {}
                  vm.clock.now = 'oops'
                }
                updateClock();
            }, 3000);
        };
        updateClock();
    })
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body data-ng-app="app">
<div data-ng-controller="Controller1 as vm">
    <h6>vm.clock.now {{vm.clock.now}} vm.now {{vm.now}}</h6>
    <h6>vm: {{vm}}</h6>
</div>

<div data-ng-controller="Controller2">
    <h6>$scope.clock.now {{clock.now}} $scope.now {{this.now}}</h6>
    <h6>this is confusing {{this}}</h6>
</div>  
<div data-ng-controller="Controller3 as vm">
    <h1>{{vm.clock.now}}</h1>
    <h6>nice scope: {{vm}}</h6>
</div>

</body>

Also see:

2
  • your answer for (2) is very ambiguous. Sure it has to do with the digest cycle, but what in using $timeout or setInterval with angular in general have to do with triggering a digest cycle ?
    – eran otzap
    Commented Dec 18, 2016 at 8:01
  • @eranotzap i've added links to more explanation on what $timeout and setInterval have to do with a digest cycle.
    – jmunsch
    Commented Dec 18, 2016 at 8:33
1

As for question 2: basically if you remove the $scope.clock.now = new Date(); instruction from outside the $timeout callback, in between two digest cycle triggered by the $timeout service, $scope.clock is actually

  • assigned to the empty object
  • then attached the now property
  • then assigned to the empty object again

So the $scope.clock.now variable is always undefined at digest time.

Detailed execution steps from Updateclock function execution start until digest cycle triggered by $timeout service :

  • $scope.clock is assigned the empty object
  • a timer is set
  • the Updateclock function completes
  • the timer expires, we enter the timeout callback function where:
    • $scope.clock.now is assigned new Date();
    • updateClock() is called recursively
      • $scope.clock is assigned the empty object again
      • a new timer is set
      • updateClock completes
    • the callback function completes
  • at this point the $timeout service triggers a digest
  • $scope.clock.now is undefined - like it was before it all begun, and like it will be at the next digest cycle

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.