1

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.

Shashank Agrawal
  • 25,161
  • 11
  • 89
  • 121

1 Answers1

3

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>
Shashank Agrawal
  • 25,161
  • 11
  • 89
  • 121
  • see my fiddle: [link](http://jsfiddle.net/40k8j2L6/). I can bind to data on the controller that way, and that is what the return statement in the controller is for. – Michael Billingham Jul 22 '16 at 05:12
  • Oh do you want me to look at the `return` thing? – Shashank Agrawal Jul 22 '16 at 05:14
  • Not sure what you mean by that. I'm just saying that the return statement has a use and that in my code if I changed the initial value of loading to true, it would show Not Loading, instead of loading. the initial binding works, just not the updates. – Michael Billingham Jul 22 '16 at 05:17