Amit G
Amit G

Reputation: 2423

Understanding Angular data binding

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?

Upvotes: 3

Views: 798

Answers (2)

IAmDranged
IAmDranged

Reputation: 3020

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

Upvotes: 1

jmunsch
jmunsch

Reputation: 24119

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:

Upvotes: 1

Related Questions