80

When I write watch handling functions I check newVal param on undefined and null. Why does AngularJS have such a behavior, but doesn't have particular utility method? So there is angular.isUndefined but not angular.isUndefinedOrNull. It isn't hard to implement that by hand but how extend angular to have that function in each controller? Tnx.

Edit:

The example:

$scope.$watch("model", function(newVal) {
    if (angular.isUndefined(newVal) || newVal == null) return;
    // do somethings with newVal
}

Is it common accepted practice to handle such a way?

Edit 2:

The JSFiddle example (http://jsfiddle.net/ubA9r/):

<div ng-app="App">
  <div ng-controller="MainCtrl"> 
      <select ng-model="model" ng-options="m for m in models">
          <option value="" class="ng-binding">Choose model</option>
      </select>
      {{model}}
  </div>
</div>

var app = angular.module("App", []);

var MainCtrl = function($scope) {
    $scope.models = ['Apple', 'Banana'];
    $scope.$watch("model", function(newVal) {
        console.log(newVal);
    });
};
Kick Buttowski
  • 6,709
  • 13
  • 37
  • 58
slo2ols
  • 1,009
  • 1
  • 8
  • 16

6 Answers6

161

You can always add it exactly for your application

angular.isUndefinedOrNull = function(val) {
    return angular.isUndefined(val) || val === null 
}
Andrew Burgess
  • 5,300
  • 5
  • 30
  • 37
Stepan Suvorov
  • 25,118
  • 26
  • 108
  • 176
  • I know that isn't always good to extend js libraries such a way but it looks very close to my searching. Actually, I am more interested in why I stuck in it. Is it a standard practice to handle undefined and null in watch handlers? – slo2ols Jul 28 '13 at 19:39
  • Well, IMHO, in good-structured application there should not be such cases. – Stepan Suvorov Jul 28 '13 at 19:43
  • got it, thx. But I still think that 'null' is a result of correct selection and it should be distinguished from 'undefined'. – Stepan Suvorov Jul 29 '13 at 06:54
  • 24
    @STEVER why would 'null' be bad in a well-structured application? If, for example, a variable should only be filled with user data when the user is logged in, null is the proper value before login and after logout. – RonLugge Apr 13 '14 at 23:15
17

My suggestion to you is to write your own utility service. You can include the service in each controller or create a parent controller, assign the utility service to your scope and then every child controller will inherit this without you having to include it.

Example: http://plnkr.co/edit/NI7V9cLkQmEtWO36CPXy?p=preview

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope, Utils) {
    $scope.utils = Utils;
});

app.controller('ChildCtrl', function($scope, Utils) {
   $scope.undefined1 = Utils.isUndefinedOrNull(1);  // standard DI
   $scope.undefined2 = $scope.utils.isUndefinedOrNull(1);  // MainCtrl is parent

});

app.factory('Utils', function() {
  var service = {
     isUndefinedOrNull: function(obj) {
         return !angular.isDefined(obj) || obj===null;
     }

  }

  return service;
});

Or you could add it to the rootScope as well. Just a few options for extending angular with your own utility functions.

BrightIntelDusk
  • 4,577
  • 2
  • 25
  • 34
lucuma
  • 18,247
  • 4
  • 66
  • 91
14

I asked the same question of the lodash maintainers a while back and they replied by mentioning the != operator can be used here:

if(newVal != null) {
  // newVal is defined
}

This uses JavaScript's type coercion to check the value for undefined or null.

If you are using JSHint to lint your code, add the following comment blocks to tell it that you know what you are doing - most of the time != is considered bad.

/* jshint -W116 */ 
if(newVal != null) {
/* jshint +W116 */
  // newVal is defined
}
Tom Spencer
  • 7,816
  • 4
  • 54
  • 50
9

Why not simply use angular.isObject with negation? e.g.

if (!angular.isObject(obj)) {
    return;
}
Pete
  • 11,313
  • 4
  • 43
  • 54
7

@STEVER's answer is satisfactory. However, I thought it may be useful to post a slightly different approach. I use a method called isValue which returns true for all values except null, undefined, NaN, and Infinity. Lumping in NaN with null and undefined is the real benefit of the function for me. Lumping Infinity in with null and undefined is more debatable, but frankly not that interesting for my code because I practically never use Infinity.

The following code is inspired by Y.Lang.isValue. Here is the source for Y.Lang.isValue.

/**
 * A convenience method for detecting a legitimate non-null value.
 * Returns false for null/undefined/NaN/Infinity, true for other values,
 * including 0/false/''
 * @method isValue
 * @static
 * @param o The item to test.
 * @return {boolean} true if it is not null/undefined/NaN || false.
 */
angular.isValue = function(val) {
  return !(val === null || !angular.isDefined(val) || (angular.isNumber(val) && !isFinite(val)));
};

Or as part of a factory

.factory('lang', function () {
  return {
    /**
     * A convenience method for detecting a legitimate non-null value.
     * Returns false for null/undefined/NaN/Infinity, true for other values,
     * including 0/false/''
     * @method isValue
     * @static
     * @param o The item to test.
     * @return {boolean} true if it is not null/undefined/NaN || false.
     */
    isValue: function(val) {
      return !(val === null || !angular.isDefined(val) || (angular.isNumber(val) && !isFinite(val)));
  };
})
Steven Wexler
  • 16,589
  • 8
  • 53
  • 80
3

lodash provides a shorthand method to check if undefined or null: _.isNil(yourVariable)

nigong
  • 1,727
  • 3
  • 19
  • 33