Weird behavior ionic in select, ng-model won't update - angularjs

I'm experiencing something weird, this example works in codepen but won't work in my Ionic app.
When I change the option in the select tag I want to show the selected value, but it won't work, it shows undefined, i've tried in many ways.
This is not the original code, the original one retrieves the values from an external API and populates the options with ngOptions (which works, it populates ok). But it won't update the value in the controller.
So I decided to make it more simple, and it still won't work:
HTML
<select ng-model="optionSelected" ng-change="selectUpdated()">
<option value="">Select an option</option>
<option value="h">Hello</option>
<option value="b">Bye</option>
</select>
JAVASCRIPT
$scope.selectUpdated = function() {
console.log('Updated');
console.log($scope.optionSelected);
};
I don't think more code is needed, the HTML is contained in ion-view and ion-content. No errors are shown, only the 'Updated' output and undefined.
When changing the option, I get undefined. But this same code in codepen works just fine.. http://codepen.io/anon/pen/YXvYmq
Can someone tell me what can be happening that triggers this odd behavior?
Thanks in advance.

Found the solution, pass the ngModel property as a parameter in the ngChange.
HTML
<select ng-model="optionSelected" ng-change="selectUpdated(optionSelected)">
<option value="">Select an option</option>
<option value="h">Hello</option>
<option value="b">Bye</option>
</select>
JS
$scope.selectUpdated = function(optionSelected) {
console.log('Updated');
console.log(optionSelected);
};

I was having the same problem today and had to create a workaround to use the select normally.
javascript
$scope.updatePreferredLanguageValue = function() {
$scope.PreferredLanguage = this.PreferredLanguage;
};
html
<select ng-model="PreferredLanguage" ng-options="Language.id as Language.name for Language in LanguageList" id="LanguageListSelect" name="LanguageListSelect" ng-change="updatePreferredLanguageValue()">
</select>
So basically I have a method that is called when the value is changed that makes sure the change is set on the $scope variable. Not pretty but it works.

Try to use $parent in your ng-model and call it from your controller.
Example
<select ng-model="$parent.selectedCar">
<option>...</option>
</select>
Reference: https://github.com/angular/angular.js/wiki/Understanding-Scopes

Related

Select not updating when model is updated in AngularJS

When I update the model, a select box is not getting updated to the value in the model. The select has all the valid options, however, the value from the model is not being selected. In the code below, the value in the model is "FACEBOOK". The mapping to the model is correct because value from the select box saves correctly. The issue is occurring when I load the model on page display.
Here is the html:
<select
class="form-control"
required
ng-model="channel.channeltype"
ng-options="obj.name for obj in contactchannels track by obj.id">
</select>
The generated html is:
<select ng-options="obj.name for obj in contactchannels track by obj.id">
<option selected="?" value="selected"></option>
<option label="Facebook" value="FACEBOOK">Facebook</option>
<option label="Skype" value="SKYPE">Skype</option>
<option label="Instagram" value="INSTAGRAM">Instagram</option>
</select>
thanks in advance,
Use ng-selected instead of selected. You can make it true and false.
And also show how you are doing in JS file with scope.
If it doesn't work like this, then give ng-change="some_func()" and define that function in JS, $scope.some_func = function() {}

Using ng-selected in combobox return undefined in AngularJS

I have a problem when ng-selected with the following code:
HTML
<select class="form-control" ng-model="producto.proveedor">
<option ng-selected="data.id_proveedor == proveedor.id" ng-repeat="proveedor in proveedores" value="{{proveedor}}">{{proveedor.nombre_empresa}}</option>
</select>
Controller
app.controller("EditarProductoController", function editController($scope,$routeParams,$filter,$location){
$scope.textButton = "Editar producto";
$scope.producto = $filter('filter')($scope.productos, {id:$routeParams.id})[0];
$scope.editarUsuario = function(){
alert($scope.producto["proveedor"]);
$location.url("/");
}
})
If I remove "ng-selected" from the code, it works fine
The code works perfect, the problem is that when I load the form return in the value combobox "undefined", it is rare because the visual part works well, then I can solve the problem if I select a different item of the combobox and re-select the original, it is Very annoying to the client, does anyone know how to fix this bug?
While your post doesn't show it, I think the UI is being rendered before "productos" gets populated with data from the database, you could wait for the promise to end with ng-if
<div ng-if="productos">
<select class="form-control" ng-model="producto.proveedor">
<option ng-selected="data.id_proveedor == proveedor.id" ng-repeat="proveedor in proveedores" value="{{proveedor}}">{{proveedor.nombre_empresa}}
</option>
</select>
</div>

Angular ng-model select option first element empty

HTML:
<select ng-model="item.visible">
<option value="0">NO</option>
<option value="1">YES</option>
</select>
ITEM:
$scope.item.visible = 1; //doesn't work
$scope.item.visible = "1" //works fine
I absolutely don't understand why first solution doesn't work and my problem is that I'm getting this value from database and I can't change it to string. I think solution could be use a directive. But I'm sure there will be much better solution.
Thanks for help.
It doesn't work because Angular uses strict comparison of the model value with the value bound to option. If you can't use string value as model you could cast it in HTML with ngInit directive:
<select ng-model="item.visible" ng-init="item.visible=item.visible + ''">
<option value="0">NO</option>
<option value="1">YES</option>
</select>
then it will work with both $scope.item.visible = 1; and $scope.item.visible = "1";.
Demo: http://plnkr.co/edit/kZJbVRtyHQ19LUbDALFx?p=preview

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

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.
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
Here is a modified plunker that works as intended: http://plnkr.co/edit/Y8OSvmrG3u0XjnCU3ah5?p=preview.
The main change was using ng-if in place of ng-show. This forces angular to recompile/link the html whenever it is rendered:
<div ng-if="someDynamicArrayOfValues">
...
</div>
Also ng-change, from the original plunker, shouldn't be necessary, and there were a couple of typos fixed.
It works a whole lot better when you use ng-options on your select element instead of nesting option with ng-repeat.
https://docs.angularjs.org/api/ng/directive/select
Then you are capable of setting the ng-model with ng-init.
You can try to set the initial value of mySelectedValue in your Controller like so:
$scope.mySelectedValue = '';
I have created example for your problem in plnkr.
Visit: plnkr.co/edit/rKyjijGWSL1IKy51b8Tv?p=preview
You are going about it the reverse way. ng-model reflects the state of the <select> and is two-way bound.
You just need to set your mySelectedValue to what you want <select> to select first, and no other tricks are required.
So, in the controller, do something like the following:
$scope.mySelectedValue = someDynamicArrayOfValues[0];
And remove the ng-selected and the <option ng-repeat...> from <select>:
<select ng-model="mySelectedValue"
ng-options="value for value in someDynamicArrayOfValues">
<option value="">--</option>
</select>

Why does AngularJS include an empty option in select?

I've been working with AngularJS for the last few weeks, and the one thing which is really bothering me is that even after trying all permutations or the configuration defined in the specification at http://docs.angularjs.org/api/ng.directive:select, I still get an empty option as the first child of select element.
Here's the Jade:
select.span9(ng-model='form.type', required, ng-options='option.value as option.name for option in typeOptions');
Here the controller:
$scope.typeOptions = [
{ name: 'Feature', value: 'feature' },
{ name: 'Bug', value: 'bug' },
{ name: 'Enhancement', value: 'enhancement' }
];
Finally, here's the HTML which gets generated:
<select ng-model="form.type" required="required" ng-options="option.value as option.name for option in typeOptions" class="span9 ng-pristine ng-invalid ng-invalid-required">
<option value="?" selected="selected"></option>
<option value="0">Feature</option>
<option value="1">Bug</option>
<option value="2">Enhancement</option>
</select>
What do I need to do to get rid of it?
P.S.: Things work without this as well, but it just looks odd if you use select2 without multiple selection.
The empty option is generated when a value referenced by ng-model doesn't exist in a set of options passed to ng-options. This happens to prevent accidental model selection: AngularJS can see that the initial model is either undefined or not in the set of options and don't want to decide model value on its own.
If you want to get rid of the empty option just select an initial value in your controller, something like:
$scope.form.type = $scope.typeOptions[0].value;
Here is the jsFiddle: http://jsfiddle.net/MTfRD/3/
In short: the empty option means that no valid model is selected (by valid I mean: from the set of options). You need to select a valid model value to get rid of this empty option.
If you want an initial value, see #pkozlowski.opensource's answer, which FYI can also be implemented in the view (rather than in the controller) using ng-init:
<select ng-model="form.type" required="required" ng-init="form.type='bug'"
ng-options="option.value as option.name for option in typeOptions" >
</select>
If you don't want an initial value, "a single hard-coded element, with the value set to an empty string, can be nested into the element. This element will then represent null or "not selected" option":
<select ng-model="form.type" required="required"
ng-options="option.value as option.name for option in typeOptions" >
<option style="display:none" value="">select a type</option>
</select>
Angular < 1.4
For anyone out there that treat "null" as valid value for one of the options (so imagine that "null" is a value of one of the items in typeOptions in example below), I found that simplest way to make sure that automatically added option is hidden is to use ng-if.
<select ng-options="option.value as option.name for option in typeOptions">
<option value="" ng-if="false"></option>
</select>
Why ng-if and not ng-hide? Because you want css selectors that would target first option inside above select to target "real" option, not the one that's hidden. It gets useful when you're using protractor for e2e testing and (for whatever reason) you use by.css() to target select options.
Angular >= 1.4
Due to the refactoring of the select and options directives, using ng-if is no longer a viable option so you gotta turn to ng-show="false" to make it work again.
Maybe useful for someone:
If you want to use plain options instead of ng-options, you could do like below:
<select ng-model="sortorder" ng-init="sortorder='publish_date'">
<option value="publish_date">Ascending</option>
<option value="-publish_date">Descending</option>
</select>
Set the model inline. Use ng-init to get rid of empty option
Something similar was happening to me too and was caused by an upgrade to angular 1.5.ng-init seems to be being parsed for type in newer versions of Angular. In older Angular ng-init="myModelName=600" would map to an option with value "600" i.e. <option value="600">First</option> but in Angular 1.5 it won't find this as it seems to be expecting to find an option with value 600 i.e <option value=600>First</option>. Angular would then insert a random first item:
<option value="? number:600 ?"></option>
Angular < 1.2.x
<select ng-model="myModelName" ng-init="myModelName=600">
<option value="600">First</option>
<option value="700">Second</option>
</select>
Angular > 1.2
<select ng-model="myModelName" ng-init="myModelName='600'">
<option value="600">First</option>
<option value="700">Second</option>
</select>
Among the multitudes of answers here, I figured I'd repost the solution that worked for me and met all of the following conditions:
provided a placeholder/prompt when the ng-model is falsy (e.g. "--select region--" w. value="")
when ng-model value is falsy and user opens the options dropdown, the placeholder is selected (other solutions mentioned here make the first option appear selected which can be misleading)
allow the user to deselect a valid value, essentially selecting the falsy/default value again
code
<select name="market_vertical" ng-model="vc.viewData.market_vertical"
ng-options="opt as (opt | capitalizeFirst) for opt in vc.adminData.regions">
<option ng-selected="true" value="">select a market vertical</option>
</select>
src
original q&a - https://stackoverflow.com/a/32880941/1121919
A quick solution:
select option:empty { display:none }
Hope it helps someone. Ideally, the selected answer should be the approach but if in case that's not possible then should work as a patch.
Yes ng-model will create empty option value, when ng-model property undefined. We can avoid this, if we assign object to ng-model
Example
angular coding
$scope.collections = [
{ name: 'Feature', value: 'feature' },
{ name: 'Bug', value: 'bug' },
{ name: 'Enhancement', value: 'enhancement'}
];
$scope.selectedOption = $scope.collections[0];
<select class='form-control' data-ng-model='selectedOption' data-ng-options='item as item.name for item in collections'></select>
Important Note:
Assign object of array like $scope.collections[0] or $scope.collections[1] to ng-model, dont use object properties. if you are getting select option value from server, using call back function, assign object to ng-model
NOTE from Angular document
Note: ngModel compares by reference, not value. This is important when binding to an array of objects. see an example http://jsfiddle.net/qWzTb/
i have tried lot of times finally i found it.
Though both #pkozlowski.opensource's and #Mark's answers are correct, I'd like to share my slightly modified version where I always select the first item in the list, regardless of its value:
<select ng-options="option.value as option.name for option in typeOptions" ng-init="form.type=typeOptions[0].value">
</select>
I'm using Angular 1.4x and I found this example, so I used ng-init to set the initial value in the select:
<select ng-init="foo = foo || items[0]" ng-model="foo" ng-options="item as item.id for item in items"></select>
I faced the same issue. If you are posting an angular form with normal post then you will face this issue, as angular don't allow you to set values for the options in the way you have used. If you get the value of "form.type" then you will find the right value. You have to post the angular object it self not the form post.
A simple solution is to set an option with a blank value "" I found this eliminates the extra undefined option.
Ok, actually the answer is way simple: when there is a option not recognized by Angular, it includes a dull one.
What you are doing wrong is, when you use ng-options, it reads an object, say [{ id: 10, name: test }, { id: 11, name: test2 }] right?
This is what your model value needs to be to evaluate it as equal, say you want selected value to be 10, you need to set your model to a value like { id: 10, name: test } to select 10, therefore it will NOT create that trash.
Hope it helps everybody to understand, I had a rough time trying :)
This solution works for me:
<select ng-model="mymodel">
<option ng-value="''" style="display:none;" selected>Country</option>
<option value="US">USA</option>
</select>
This worked for me
<select ng-init="basicProfile.casteId" ng-model="basicProfile.casteId" class="form-control">
<option value="0">Select Caste....</option>
<option data-ng-repeat="option in formCastes" value="{{option.id}}">{{option.casteName}}</option>
</select>
This works perfectly fine
<select ng-model="contact.Title" ng-options="co for co in['Mr.','Ms.','Mrs.','Dr.','Prof.']">
<option style="display:none" value=""></option>
</select>
the way it works is, that this gives the first option to be displayed before selecting something and the display:none removes it form the dropdown so if you want you can do
<select ng-model="contact.Title" ng-options="co for co in['Mr.','Ms.','Mrs.','Dr.','Prof.']">
<option style="display:none" value="">select an option...</option>
</select>
and this will give you the select and option before selecting but once selected it will disappear, and it will not show up in the dropdown.
Try this one in your controller, in the same order:
$scope.typeOptions = [
{ name: 'Feature', value: 'feature' },
{ name: 'Bug', value: 'bug' },
{ name: 'Enhancement', value: 'enhancement' }
];
$scope.form.type = $scope.typeOptions[0];
Here is the fix :
for a sample data like :
financeRef.pageCount = [{listCount:10,listName:modelStrings.COMMON_TEN_PAGE},
{listCount:25,listName:modelStrings.COMMON_TWENTYFIVE_PAGE},
{listCount:50,listName:modelStrings.COMMON_FIFTY_PAGE}];
The select option should be like this:-
<select ng-model="financeRef.financeLimit" ng-change="financeRef.updateRecords(1)"
class="perPageCount" ng-show="financeRef.showTable" ng-init="financeRef.financeLimit=10"
ng-options="value.listCount as value.listName for value in financeRef.pageCount"
></select>
The point being when we write value.listCount as value.listName, it automatically populates the text in value.listName but the value of the selected option is value.listCount although the values my show normal 0,1,2 .. and so on !!!
In my case, the financeRef.financeLimit is actually grabbing the value.listCount and I can do my manipulation in the controller dynamically.
I would like to add that if the initial value comes from a binding from some parent element or 1.5 component, make sure that the proper type is passed. If using # in binding, the variable passed will be string and if the options are eg. integers then the empty option will show up.
Either parse properly the value in init, or binding with < and not # (less recommended for performance unless necessary).
Simple solution
<select ng-model='form.type' required><options>
<option ng-repeat="tp in typeOptions" ng-selected="
{{form.type==tp.value?true:false}}" value="{{tp.value}}">{{tp.name}}</option>
A grind solution with jQuery when you haven't the control of the options
html:
<select id="selector" ng-select="selector" data-ng-init=init() >
...
</select>
js:
$scope.init = function () {
jQuery('#selector option:first').remove();
$scope.selector=jQuery('#selector option:first').val();
}
If you use ng-init your model to solve this problem:
<select ng-model="foo" ng-app ng-init="foo='2'">
i had the same problem,
i (removed "ng-model") changed this :
<select ng-model="mapayear" id="mapayear" name="mapayear" style=" display:inline-block !important; max-width: 20%;" class="form-control">
<option id="removable" hidden> Selecione u </option>
<option selected ng-repeat="x in anos" value="{{ x.ano }}">{{ x.ano }}
</option>
</select>
to this:
<select id="mapayear" name="mapayear" style=" display:inline-block !important; max-width: 20%;" class="form-control">
<option id="removable" hidden> Selecione u </option>
<option selected ng-repeat="x in anos" value="{{ x.ano }}">{{ x.ano }}
</option>
</select>
now its working, but in my case it was cause ive deleted that scope from ng.controller, check if u didn't do the same.
The only thing worked for me is using track by in ng-options, like this:
<select class="dropdown" ng-model="selectedUserTable" ng-options="option.Id as option.Name for option in userTables track by option.Id">
Refer the example from angularjs documentation how to overcome these issues.
Go to this documentation link here
Find 'Binding select to a non-string value via ngModel parsing / formatting'
There u can see there, directive called 'convertToNumber' solve the issue.
It works for me. Can also see how it works here
We can use CSS to hide the first option , But it wont work in IE 10, 11. The best way is to remove the element using Jquery. This solution works for major browser tested in chrome and IE10 ,11
Also if you are using angular , sometime using setTimeout works
$scope.RemoveFirstOptionElement = function (element) {
setTimeout(function () {
$(element.children()[0]).remove();
}, 0);
};

Resources