Search code examples
javascriptangularjsjavascript-databinding

Binding to primitive value on controller


I am trying to bind to a boolean variable on my controller's scope to indicate whether or not a loading animation should be displayed. However, the following code does not work. The function inside $timeout runs, but the view is not updated.

When I inspect the scope using the chrome angular extension, I see that ctrl.loading is true.

Is this because of booleans being value types in javascript, as opposed to reference types?

My guess is that the view is literally binding to true, and not to the location of a boolean value which would change.

How do I get the view to bind to the variable, and not to the value, the variable has initially?

controller:

function TestController($scope,$timeout){
    "use strict";

    var loading=true;

    $timeout(function(){
        loading=false;
    }, 1000);

    return {
        loading:loading
    }

}

template:

<div>
    <h1 ng-show="ctrl.loading">Loading</h1>
    <h1 ng-hide="ctrl.loading">Not Loading</h1>
</div>

The abovecode is just an example, really I would set the value after a get request wqas returned.

$http.get().then(function() {
    loading=false;
}, function() {
    loading=false;
})

but the effect is the same.


Solution

  • You are binding the loading variable wrongly. You either need to register that variable loading to the $scope or to the this variable. See the below working example:

    var app = angular.module("sa", []);
    
    app.controller("TestController", TestController);
    
    function TestController($scope, $timeout) {
      "use strict";
      var vm = this;
    
      vm.loading = true;
    
      $timeout(function() {
        vm.loading = false;
      }, 2000);
    
    }
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
    
    
    <div ng-app="sa" ng-controller="TestController as ctrl">
      <h1 ng-show="ctrl.loading">Loading</h1>
      <h1 ng-hide="ctrl.loading">Not Loading</h1>
    </div>

    Also, the return block in the controller is of no use.

    Edit

    Now, I understand your question. This is the first time I saw this feature of returning from the controller. After half an hour of researching, I found out that you can't expect a primitive type to be passed by reference in Javascript. You need to use some object.

    See the scope inheritance problem to get a gist: https://github.com/angular/angular.js/wiki/Understanding-Scopes

    To fix this, you can alter your code like below:

    var app = angular.module("sa", []);
    
    app.controller("TestController", TestController);
    
    function TestController($scope, $timeout) {
      "use strict";
      var myData = {};
    
      myData.loading = true;
    
      $timeout(function() {
        myData.loading = false;
      }, 2000);
    
      return {
        myData: myData
      };
    }
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
    
    <div ng-app="sa" ng-controller="TestController as ctrl">
      <h1 ng-show="ctrl.myData.loading">Loading</h1>
      <h1 ng-hide="ctrl.myData.loading">Not Loading</h1>
    </div>