2

Let's say in the condition of AngularJS's ngShow, what if a property doesn't exist?

For example, if vm.foo is 1, then what if in the HTML, there is a

<div ng-show="myCtrl.foo.bar.wa.la">
    hello
</div>

and what if it is

<div ng-show="!myCtrl.foo.bar.wa.la">
    hello
</div>

Example at: https://jsfiddle.net/4yg2ocy6/1/

(If it is pure JavaScript, it will raise an exception)

I suspect that

myCtrl.foo.bar.wa.la

is treated by AngularJS as the same as:

(myCtrl.foo && myCtrl.foo.bar && myCtrl.foo.bar.wa && myCtrl.foo.bar.wa.la)

and

!myCtrl.foo.bar.wa.la

is the same as

!(myCtrl.foo && myCtrl.foo.bar && myCtrl.foo.bar.wa && myCtrl.foo.bar.wa.la)

but I can't find any documentation about it.

Another possibility is that it treats (myCtrl.foo.bar.wa.la) as one unit, if Angular can evaluate it, then return the result, but if it raises an exception, catch it and return false. So for !myCtrl.foo.bar.wa.la, it will treat it as !false and therefore is true.

Is there a more definite spec for this?

nonopolarity
  • 146,324
  • 131
  • 460
  • 740

1 Answers1

3

The short (and sweet) answer

myCtrl.foo.bar.wa.la will evaluate to undefined which doesn't trigger ngShow.

The long answer

One important thing to note from Angular Expressions vs. JavaScript Expressions:

Forgiving: In JavaScript, trying to evaluate undefined properties generates ReferenceError or TypeError. In Angular, expression evaluation is forgiving to undefined and null.

This means that something like a.very.long.reference.which.does.not.exist won't throw an error and will evaluate to undefined. See this example:

angular
  .module('myApp', [])
  .controller('MainCtrl', function() {
    var vm = this;

    vm.typeOf = function(value) {
      return typeof value;
    };
  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.3/angular.min.js"></script>

<div ng-app="myApp">
  <div ng-controller="MainCtrl as vm">
    <div>{{ vm.typeOf(a.very.long.reference.which.does.not.exist) }}</div>
  </div>
</div>

Now, to answer your questions. Internally, both ngHide and ngShow, use a basic check to see if the expression is true or not. They do something like: if (expression) { // do this } else { // do that }.

Since both ngHide and ngShow are triggered when the expression is truthy, and that a.very.long.reference.which.does.not.exist evaluates to undefined, is clear to see why they aren't triggered when a property doesn't exist.

Some expressions and their evaluation:

undefined ? 'truthy' : 'falsy' // 'falsy'
null ? 'truthy' : 'falsy' // 'falsy'

// Booleans
true ? 'truthy' : 'falsy' // 'truthy'
false ? 'truthy' : 'falsy' // 'falsy'

// Numbers
1 ? 'truthy' : 'falsy' // 'truthy'
0 ? 'truthy' : 'falsy' // 'falsy'
0.00001 ? 'truthy' : 'falsy' // 'truthy'
NaN ? 'truthy' : 'falsy' // 'falsy'

// Strings
'something' ? 'truthy' : 'falsy' // 'truthy'
'0' ? 'truthy' : 'falsy' // 'truthy'
'' ? 'truthy' : 'falsy' // 'falsy'

({}) ? 'truthy' : 'falsy' // 'truthy'
[] ? 'truthy' : 'falsy' // 'truthy'
(new Date()) ? 'truthy' : 'falsy' // 'truthy'
Cosmin Ababei
  • 7,003
  • 2
  • 20
  • 34
  • 1
    Your quote is correct, Angular uses the `$watch` service on the value of `attr.ngHide` (ngHide is just an example). Watch in turn uses the `$parse` service to parse the passed angular expression and that expression follows the rule you quoted above. [ngHide source](https://github.com/angular/angular.js/blob/master/src/ng/directive/ngShowHide.js#L326) [watch source](https://github.com/angular/angular.js/blob/master/src/ng/rootScope.js#L387). for future reference in the docs clicking 'view source` takes you to the actual source so you can see exactly what is happening. – ste2425 Mar 10 '16 at 14:42