In AngularJS's ngShow or ngHide, or conditiona

2019-05-25 03:36发布

问题:

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?

回答1:

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'