38

I couldn't find an elegant way for setting null values with a <select> using AngularJS.

HTML :

<select ng-model="obj.selected">
  <option value=null>Unknown</option>
  <option value="1">Yes</option>
  <option value="0">No</option>
</select>

{{obj}}

JS :

$scope.obj ={"selected":null};

When the page is loaded, the first option is selected, which is good, and the output is {"selected":null}. When that first option is reselected after having switch to another one, the output becomes {"selected":"null"} (with the quotes), which is not what I would expect.

Running example : http://plnkr.co/edit/WuJrBBGuHGqbKq6yL4La

I know that the markup <option value=null> is not correct. I also tried with <option value=""> but it corresponds to an empty String and not to null : the first option is therefore not selected and another option which disappears after the first selection is selected by default.

Any idea ?

4
  • 1
    What do you need this plain null for? Commented May 15, 2014 at 18:43
  • You can't use null. It ISNT a value, and angular needs a value to track. Commented May 15, 2014 at 18:45
  • 3
    @creimers null is permitted by the JSON specifications. I do not want to have some code which converts empty string to null (empty string may have another semantics) Commented May 15, 2014 at 18:58
  • angularjs is inconsistent when it comes to the default select option stackoverflow.com/questions/23643712/… Commented Sep 2, 2015 at 7:36

9 Answers 9

40

This should work for you:

Controller:

  function MyCntrl($scope) {
    $scope.obj ={"selected":null};
    $scope.objects = [{id: 1, value: "Yes"}, {id: 0, value: "No"}]
  }

Template:

  <div ng-controller="MyCntrl">

    <select ng-model="obj.selected"
            ng-options="value.id as value.value for value in objects">
            <option value="">Unknown</option>
    </select>

<br/>
     {{obj}}
  </div>

Working plnkr

You should use ng-options with select.

Sign up to request clarification or add additional context in comments.

3 Comments

This solution worked. I did a small change : the objects list is defined in the ng-options tag in order to keep my controller clean. Thanks !
I wish this solution was explained further to understand how everything works.
Could you please update your plnkr to use newer version of Angular? For instance it does not work with version 1.4.1.
19

You can use the ngOptions directive on the select. According to the documentation:

Optionally, a single hard-coded <option> element, with the value set to an empty string, can be nested into the <select> element. This element will then represent the null or "not selected" option. See example below for demonstration.

<select ng-model="obj.selected" ng-options="key as label for (key, label) in ['No', 'Yes']">
  <option value="">Unknown</option>
</select>

It's obviously a better idea to define the options list directly in the controller.

Comments

3

Try using ng-options instead of manually creating tags, as in this example, lightly-edited from the Angular docs:

http://plnkr.co/edit/DVXwlFR6MfcfYPNHScO5?p=preview

The operative parts here are lines 17, defining a 'colors' object, and the ng-options attributes iterating over those colors to create options.

Comments

2

If you REALLY want to use null, see below. You need to use ng-options and let Angular handle the mapping:

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Color selector</title>

  <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.8/angular.min.js"></script>

</head>
<body ng-app="">
    <script>
  function MyCntrl($scope) {
    $scope.obj ={"selected":null};
    $scope.objStates = [{key:"Unknown", value:null}, {key:"Yes", value:1}, {key:"No", value:0}]

    $scope.$watch('obj.selected', function(newVal){
      console.log(newVal);
    })
  }
  </script>
  <div ng-controller="MyCntrl">

    <select ng-model="obj.selected" ng-options="state.value as state.key for state in objStates">
    </select>

<br/>
     {{obj}}
  </div>
</body>
</html>

1 Comment

This looks nice and that is what I'd like to do, but it doesn't work. Try this Plunker. If you set the value to Yes and then back to Unknown, you'll notice that there is a en extra bogus option. @Wawy's solution doesn't have this problem.
2

I ran into the same Problem but could not solve it via 'ng-options'. My solution is:

module.directive('modelToNull', [function () {
    return {
        scope: {
            check: "&modelToNull"
        },
        require: 'ngModel',
        link: function ($scope, element, attrs, ngModelController) {
            ngModelController.$parsers.push(function (value) {
                return value == null || $scope.check({value: value}) ? null : value;
            });
        }
    };
}]);

You can use it like this:

<select ng-model="obj.selected" model-to-null="value == 'null'">
  <option value="null">Unknown</option>
  <option value="1">Yes</option>
  <option value="0">No</option>
</select>

1 Comment

If you can manage option values client side, it could be implemented without matcher and scope: link: function(scope, element, attrs, ngModelController) { ngModelController.$formatters.push(function (value) { return value == null ? 'null' : value;}); ngModelController.$parsers.push(function(value) { return value === 'null' ? null : value; }); } Plus this one will be working both directions.
0

Can you try to use parseInt on the value? For example, both "1" and "0" will equal their respective integer values. If you run the empty string through parseInt you can easily get NaN.

> parseInt("") = NaN

> parseInt("0") === 0

> parseInt("1") === 1

Comments

0

Without the possibility of using ng-options I present another fix.

I've been battling this a couple of months now, using solutions presented on this question and I don't know how nobody posted this:

<option value="null"></option>

This should work on Angular 1.6 and above for sure when you are using ng-repeat for options instead of ng-options.

It's not ideal but since we are used to work on legacy code this simple fix could save your day.

Comments

-1

the only way you can achieve that is by using a onchange event and restoring the object as initialized any other attempt to set the selected to null will remove the property from the object.

$scope.setValue=function(val){
  if($scope.obj.selected=="null")
     $scope.obj ={"selected":null};
}

<select ng-change="setValue()" ng-model="obj.selected">
  <option value=null ng-click="obj.selected=null">Unknown</option>
  <option value="1">Yes</option>
  <option value="0">No</option>
</select>

this is a bad idea, you should always have values in your model instead of playing around with null and undefined

3 Comments

I have to disagree ... When nothing is selected, the nullvalue is more meaningful than the empty string. As shown in the selected answer, this not 'playing', the code is clearer because I do not have do some interpretation over the empty string. Null is null from the front-end to the database.
from data management point of view you are right it makes sense using null values. when talking about DOM and browser compatibility is a more complicated issue, since having some value assigned to null could have different outcomes and unwanted results...
Im dealing with a similar issue, and <option value ></option> parses value into null, fwiw
-2

This is much easier on Angular2/Angular where you can just use

<option [value]="null">Unknown</option>

This value is no longer a string, but a real null value.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.