Search code examples
angularjshtml-selectangular-ngmodel

Angular JS - Select box has a blank option at top


The problem I had was that the select had a blank option at the top even though the model had a value corresponding to the value of the first option.

JavaScript:

var MyApp, Day;

Day = (function() {
  function Day() {}
  Day.MON = 'Mon';
  Day.TUE = 'Tue';
  Day.WED = 'Wed';
  return Day;
})();

MyApp = angular.module('MyApp1', []);
MyApp.controller('MyController', function($scope) {
  $scope.myDay = Day.MON;
  $scope.Day = Day;
});

HTML:

<div ng-app="MyApp1">
  <div ng-controller="MyController">
    Current value: {{myDay}}
    <select ng-model="myDay">
      <option ng-value="Day.MON">
        {{Day.MON}}
      </option>
      <option ng-value="Day.TUE">
        {{Day.TUE}}
      </option>
      <option ng-value="Day.WED">
        {{Day.WED}}
      </option>
    </select>
  </div>
</div>

Output HTML:

...
Current value: Mon
<select class="ng-pristine ng-valid" ng-model="myDay"><option value="? string:Mon ?"></option>
  <option class="ng-binding" value="Mon" ng-value="Day.MON">
    Mon
  </option>
  <option class="ng-binding" value="Tue" ng-value="Day.TUE">
    Tue
  </option>
  <option class="ng-binding" value="Wed" ng-value="Day.WED">
    Wed
  </option>
</select>
...

Note that the model has the correct value and that there is a blank option added directly inside the select element.

Demo: http://jsfiddle.net/ndLtLmrv/

There are many similar questions on StackOverflow but most of them seems to be caused by an uninitialised model.


Solution

  • After some hours of searching for an answer and debugging (since my actual code is a lot larger I tried many different things) I finally found the solution! It was really simple actually. All I had to do was to remove all the whitespace inside the option elements.

    New HTML:

    ...
    <select ng-model="myDay">
      <option ng-value="Day.MON">{{Day.MON}}</option>
      <option ng-value="Day.TUE">{{Day.TUE}}</option>
      <option ng-value="Day.WED">{{Day.WED}}</option>
    </select>
    ...
    

    This will give the expected output.

    The reason why I didn't write like this from the beginning was that I was using HAML, which added the new line and indentation automatically. I solved this by adding a < to the %option (see HAML whitespace removal).

    I still don't see why this happened though as I have similar selects which work just fine even though they have whitespace inside the option. Now I've got a solution at least.

    EDIT:

    Now I think I know why the problem occured. It seems that angular compares the value in ng-model with the option values before ng-value is evaluated. Since the options didn't have any values, the model was compared to the content of the options instead. This explains why it didn't work in the first case (there's too much whitespace) while it worked when I removed the whitespace.

    Thus, the solution I proposed here only works if the content of the option is the same as its value. By manually adding a value the problem is solved.

    This should be a more correct solution to the initial problem:

    ...
    <select ng-model="myDay">
      <option ng-value="Day.MON" value="{{Day.MON}}">
        Mon
      </option>
      <option ng-value="Day.TUE" value="{{Day.TUE}}">
        Tue
      </option>
      <option ng-value="Day.WED" value="{{Day.WED}}">
        Wed
      </option>
    </select>
    ...