3

I have no problem getting ng-show to work when I use a scoped variable:

(excerpt from html file:)

<li ng-show="hasBattery">
  <span>Battery</span>
  <dl>
    <dt>Type</dt>
    <dd>{{phone.battery.type}}</dd>
  </dl>
</li>

using the following controller code, which works fine:

phonecatControllers.controller('PhoneDetailCtrl', ['$scope', '$routeParams', '$http',
  function($scope, $routeParams, $http) {

    function loadData() {
      // fyi, the ?date nonsense below is to avoid browser cacheing of the json file 
      $http.get('phones/' + $routeParams.phoneId + '.json' + '?' + 
                new Date().getTime()).success(function(data) {
        $scope.phone = data; 
        $scope.hasBattery = !$scope.isEmpty($scope.phone.battery.type);
        // should i call some form of $scope.$apply() here? when i do,
        // i get a digest already in progress error. ng-show seems to 
        // update fine without a call to $apply
      });
    };

    $scope.isEmpty = function(str) {
      var retVal = (typeof(str) === undefined || !str || 0 === str.length);
      alert("isempty: returning " + retVal);
      return retVal;
    };

    $scope.hasBattery = false;
    loadData();
  }
]);

Like I said, that works. When I view a page whose phone.battery.type is undefined or blank, ng-show correctly hides the div. When I view a page whose phone.battery.type is a non-empty string, ng-show correctly shows the div. All good.

Here's my question: when I use the !isEmpty(...) call directly in the ng-show expression, instead of using $scope.hasBattery as an intermediary, it doesn't work.

Here's my code for that version:

<li ng-show="{{!isEmpty(phone.battery.type)}}">
  <span>Battery</span>
  <dl>
    <dt>Type</dt>
    <dd>{{phone.battery.type}}</dd>
  </dl>
</li>

controller, with hasBattery removed:

phonecatControllers.controller('PhoneDetailCtrl', ['$scope', '$routeParams', '$http',
  function($scope, $routeParams, $http) {

    function loadData() {
      $http.get('phones/' + $routeParams.phoneId + '.json' + '?' + new Date().getTime()).success(function(data) {
        $scope.phone = data; 
        // no longer do any evaluation of isEmpty here.
        // as before, I'm not calling $scope.$apply() at all
      });
    };

    // same code as before
    $scope.isEmpty = function(str) {
      var retVal = (typeof(str) === undefined || !str || 0 === str.length);
      alert("isempty: returning " + retVal);
      return retVal;
    };

    loadData();
  }
]);

When I load a page whose phone.battery.type is a non-empty string, which I want ng-show to show, it fails to show the div. I see that isEmpty is indeed being called after the data loads, and is correctly returning false (so that ng-show's expression, !isEmpty(...), is true). But it seems like Angular is not doing anything with the value of this expression!

alert dialog box shows that isEmpty is being called and correctly returning false .

Any idea what's going on? I would think this was a $scope.$apply problem, like I've seen elsewhere on SO, but the expression does seem to be being evaluated using up to date data.

Ben Wheeler
  • 6,788
  • 2
  • 45
  • 55
  • When you evaluate an expression inside ng-show/ng-if etc. with {{}} it gets evaluated only once. – Mohammad Sepahvand Sep 19 '14 at 20:06
  • @Razah - don't think so. See: http://www.whitneyland.com/2013/02/why-does-angularjs-sometimes-use-single-braces-sometimes-double-braces-and-sometimes-no-braces.html – Ben Wheeler Sep 20 '14 at 04:13
  • @Mohammad but I'm seeing the alert called at least twice. And the last time it is called, isEmpty is returning false. So shouldn't that return value be used? Yet ng-show doesn't show the div. – Ben Wheeler Sep 20 '14 at 04:16
  • @Cyril because Eg.: http://www.whitneyland.com/2013/02/why-does-angularjs-sometimes-use-single-braces-sometimes-double-braces-and-sometimes-no-braces.html – Ben Wheeler Sep 20 '14 at 04:17
  • @Benjamin the link you provided is already more than 1 year old. The author might be using a different version of angularJS which behaves differently. Did you just try removing the `{{ }}` to see if anything changes ? See this question : http://stackoverflow.com/questions/17444394/angularjs-ng-show-ng-hide-expression-not-evaluated – Cyril Duchon-Doris Sep 20 '14 at 11:59