How do I get the ng-model of a select tag to get the initially-selected option?

Troy picture Troy · Oct 21, 2014 · Viewed 27.5k times · Source

I'm pretty new to Angular, so I may be going about this all wrong...

I have a <select> similar to the following:

<select ng-model="mySelectedValue">
    <option value="">--</option>
    <option ng-repeat="myValue in someDynamicArrayOfValues" value="{{myValue}}" ng-selected="myFunctionForDeterminingWhetherValueIsSelected(myValue)">{{myValue}}</option>
</select>

This mostly works... The dropdown initially renders with the correct option selected, and if I change the selected option, then mySelectedValue will get the new selection. However, mySelectedValue does NOT get the initially-selected option. mySelectedValue is blank until I change the value in the dropdown.

I looked at ng-init, but that seems to get evaluated before someDynamicArrayOfValues is set...

Is there a way I can get mySelectedValue to receive the value in the initially-selected <option>?


UPDATE:
I forgot to mention that I had also tried using ng-options, but haven't had any luck getting that to work in conjunction with determining which option was selected.

I've tried this:

<div ng-show="someDynamicArrayOfValues">
    <select ng-model="mySelectedValue" ng-options="arrayValue for arrayValue in someDynamicArrayOfValues" ng-selected="myFunctionForDeterminingWhetherValueIsSelected(arrayValue)">
        <option value="">--</option>
    </select>
</div>

and this:

<div ng-show="someDynamicArrayOfValues">
    <select ng-model="mySelectedValue" ng-options="arrayValue for arrayValue in someDynamicArrayOfValues" ng-init="myFunctionForSettingSelectedValue()">
        <option value="">--</option>
    </select>
</div>

but neither of those work because the select is built (and ng-init and ng-selected both get evaluated) before someDynamicArrayOfValues has been set and, therefore, before the <select> is even visible. When using <option ng-repeat="...">, the <select> doesn't get built/initialized until after someDynamicArrayOfValues is set, which is why I had been going that direction.

Is there a way to get the ng-options technique to work while, at the same time, having the select dependent on someDynamicArrayOfValues (if ng-options is the better way to go)?


UPDATE 2:
Here's a Plunker (modified from ababashka's answer) that is a little closer to what I'm ultimately trying to achieve: http://plnkr.co/edit/Kj4xalhI28i5IU0hGBLL?p=preview. It's not quite there yet... I'd like it to have each of the 3 dropdowns set with the closest-matching dynamic value once someDynamicArrayOfValues is set.

Answer

ababashka picture ababashka · Oct 21, 2014

I think that it will be good it you will use ng-options attribute of select tag. It's an angular directive which creates options according to Array of options. You can take a look at select documentation
If you use your code - your function myFunctionForDeterminingWhetherValueIsSelected works twice for every option at initialization and once for every option item when you select some another option.

Demo with your code: http://plnkr.co/edit/0IVNLHiw3jpz4zMKcB0P?p=preview

Demo for select you could see at description of select directive.

Update

At first, to see when value is changed - you need to use ng-change attribute of select tag, like this:

<select ng-model="mySelectedValue" 
  ng-options="myValue for myValue in someDynamicArrayOfValues"
  ng-change="myFunctionForDeterminingWhetherValueIsSelected()">
  <option value="">--</option>
</select>

Then, i don't know how does myFunctionForSettingSelectedValue look like, but there are 2 variants:

  • This function returns some value - then you need to use ng-init next way.

Controller:

  $scope.someInitFunc = function () {
    return 'One';
  };

HTML:

<select ng-model="mySelectedValue" 
      ng-options="myValue for myValue in someDynamicArrayOfValues"
      ng-change="myFunctionForDeterminingWhetherValueIsSelected()"
      ng-init="mySelectedValue = someInitFunc()">
      <option value="">--</option>
</select>
  • You set value of mySelectedValue in this function - then you do this.

Controller:

$scope.someInitFunc = function () {
  $scope.mySelectedValue = 'One';
};

HTML:

<select ng-model="mySelectedValue" 
  ng-options="myValue for myValue in someDynamicArrayOfValues"
  ng-change="myFunctionForDeterminingWhetherValueIsSelected()"
  ng-init="someInitFunc()">
  <option value="">--</option>
</select>

I have created an example which implements the first version of using ng-init. When new value is selected - it's printed to console.

Also, i moved options to the options.json file. So options are initialized just after ajax request was finished. Everything works great.

Demo: http://plnkr.co/edit/pzjxxTnboKJXJYBGcgNb?p=preview

Update 2

Hello again. I think you don't need to have any ng-init according to your requirements. You can just initiate values of your model when http request is finished. Also i don't understand why do you need ng-change function in this case.

Here is modified code you need from your plunk where values of ng-models are initiated after options are loaded.

JavaScript:

.controller('MainCtrl', function($scope, $http) {
  $scope.someStaticArrayOfValues = ['One', 'Two', 'Three'];
  $scope.mySelectedValues = {};
  $http.get('options.json').then(
    function (response) {
      $scope.someDynamicArrayOfValues = response.data;
      for (var i = 0; i < $scope.someStaticArrayOfValues.length; ++i) {
        $scope.someDynamicArrayOfValues.some(function (value) {
          if (value.substring(0, $scope.someStaticArrayOfValues[i].length) === $scope.someStaticArrayOfValues[i]) {
            $scope.mySelectedValues[$scope.someStaticArrayOfValues[i]] = value;
            return true;
          }
        });
      }
    },
    function (response) {
      console.log('ERROR!');
    }
  );
});

HTML:

  <body ng-controller="MainCtrl">
    <p>Hello {{name}}!</p>

    <div ng-show="someDynamicArrayOfValues">
      <ul>
        <li ng-repeat="staticValue in someStaticArrayOfValues">
          {{staticValue}} - 
          <select ng-model="mySelectedValues[staticValue]" 
            ng-options="myValue for myValue in someDynamicArrayOfValues">
            <option value="">--</option>
          </select>
          <h2>{{mySelectedValues[staticValue]}}</h2>
        </li>
      </ul>
    </div>
  </body>

Demo: http://plnkr.co/edit/9Q1MH0esGE1SIJa0m2NV?p=preview