I am trying to populate a drop-down select options list and set a default selected value using ng-model and ng-options.
I have the following code in my view:
<select ng-model="thisTour.site" ng-options="site.name for site in siteList"></select>
And in my controller:
$scope.siteList = [
{ id: 1, name: 'cycling'},
{ id: 2, name: 'walking'},
{ id: 3, name: 'holidays'}
]
$scope.thisTour.site = { id: 2, name: 'walking'};
The list is getting populated with the correct 3 options from the siteList
object, but it is not selecting walking by default as I would expect? Why not?
Now, when I change this:
$scope.thisTour.site = { id: 2, name: 'walking'};
To this:
$scope.thisTour.site = $scope.siteList[1];
Now it works. Why? Isn't it the same thing?
In my opinion the correct way to set a default value is to simply pre-fill your ng-model property with the value selected from your ng-options , angular does the rest. Essentially when you define the $scope property your select will bind to assign it the default value from your data array.
The AngularJS ng-value directive is used to set the value attribute of an input element, or a select element. It is mainly used on <radio> and <option> elements to set the bound values when these elements are selected. It is supported by <input> and <select> elements.
Definition and Usage. The ng-options directive fills a <select> element with <options>. The ng-options directive uses an array to fill the dropdown list. In many cases it would be easier to use the ng-repeat directive, but you have more flexibility when using the ng-options directive.
Definition and Usage The ng-selected directive sets the selected attribute of an <option> element in a <select> list. The option will be selected if the expression inside the ng-selected attribute returns true. The ng-selected directive is necessary to be able to shift the value between true and false .
AngularJS ng-options Directive 1 Definition and Usage. The ng-options directive fills a <select> element with <options>. The ng-options directive uses an... 2 Syntax. Supported by the <select> element. 3 Parameter Values. An expression that selects the specified parts of an array to fill the select element. More ...
Using a default select this works as expected. Option is selected and model's value is set to null when selecting this option. Same situation here. Switching to ng-select from default <select> was a pain due to ignorance of 'null' as default option.
For objects, use the ngValue input binding. Tracks the value bound to the option element. Unlike the value binding, ngValue supports binding to objects. Recently I have to build a dropdown for a simple yes/no input, which output is equivalent to a boolean type. Obviously, we can always use a checkbox for that purpose.
Because both "false" and "true" will always be truthy, which mean in the context of boolean, they are always equal true. @Input () ngValue: any: Tracks the value bound to the option element. Unlike the value binding, ngValue supports binding to objects. @Input () value: any: Tracks simple string values bound to the option element.
That is because angular looks for object equality to bind it with your syntax and inyour case $scope.siteList[1]
is not equal to { id: 2, name: 'walking'};
(2 objects are equal only if they point to the same reference). You can get around this in many ways, one easy way is to use track by
syntax with ng-options to specify track by id
, which will enable ng-option's options to be tracked by the specified property of the bound object rather than the object reference itself.
<select ng-model="thisTour.site"
ng-options="site.name for site in siteList track by site.id"></select>
You could also use the syntax to minimally set the ng-model to specify only the id using select as part in the syntax:-
Example:-
ng-options="site.id as site.name for site in siteList"
and model would just be:-
$scope.thisTour.site = 2;
angular.module('app', []).controller('ctrl', function($scope){
$scope.thisTour = {};
$scope.siteList = [
{ id: 1, name: 'cycling'},
{ id: 2, name: 'walking'},
{ id: 3, name: 'holidays'}
]
$scope.thisTour.site = { id: 2, name: 'walking'};
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<select ng-model="thisTour.site" ng-options="site.name for site in siteList track by site.id"></select>
{{thisTour.site}}
</div>
From documentation
trackexpr: - Used when working with an array of objects. The result of this expression will be used to identify the objects in the array. The trackexpr will most likely refer to the value variable (e.g. value.propertyName). With this the selection is preserved even when the options are recreated (e.g. reloaded from the server).
Also worth noting:
Do not use select as and track by in the same expression. They are not designed to work together.
This isn't the same thing because objects in javascript are passed by reference.
If you take the first example:
$scope.siteList = [
{ id: 1, name: 'cycling'},
{ id: 2, name: 'walking'},
{ id: 3, name: 'holidays'}
]
$scope.thisTour.site = { id: 2, name: 'walking'};
Then you do this:
$scope.thisTour.site.id = 3;
console.log($scope.siteList[1].id) // 2
In other words, whilst your two objects are equal in value, they aren't the same object. The ngOptions
directive sees this, so would set thisTour.site
to a blank value because it isn't one of the allowed options.
Google "passing by reference in javascript" to learn more.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With