Angularjs: Select ng-options right way - angularjs

For the select tag with angularjs i'm doing:
<select ng-init="getdata()" data-ng-model="ob.id"
data-ng-options="level.id as level.desc for level in levels"
data-ng-selected="ob.id == level.id">
<option value="0">default...</option>
</select>
... but is this the right way because there are so many other ways on the web?
getdata() gets $scope.levels array.

You don't need to write ng-selected, it's not necessary. Also ng-init should just be used in really specific cases (nginit) so as OZ mentioned it'd better to call getData() from the controller.
<select data-ng-model="ob.id"
data-ng-options="level.id as level.desc for level in levels">
<option value="0">default...</option>
</select>
Other than that the select looks correct.

Try to avoid binding to primitives (use objects instead, for instance - $scope.data). So I'd replace levels to data.levels
It's up to you where you really need getdata() call, but controller's initialisation might be a better choice.
Also, if you want to keep your View clean of data, try to declare default value in model (or in service), not in View.

Your way is one of the good way.
I have another way with some custom coding .
Here is a code for my sample.
Html code
<div class="col-sm-6 form-group">
<label for="companyName">Tenants</label>
<select class="form-control input-lg" ng-model="selectedTenant"
required ng-options="i.CompanyName for i in tenants">
</select>
</div>
Angular Code
$http.get('/tenants')
.success(function (response) {
response.push({ CompanyName: "Select", TenantId: 0 });
$scope.tenants = response;
$scope.selectedTenant = response[$scope.tenants.length - 1];
$scope.$apply();
})

Related

ng-selected not working in select field

I am trying to set the default value of a select field to a set option but its not working and I can't seem to figure out what am I doing wrong?
In my controller I have:
$scope.interp_id = "2"; // set the default id
$http.get("web/controllers/get.php")
.then(function (response) {
$scope.interpreters = response.data.records;
});
get.php is a php file that returns json (this is working properly).
My select looks like:
<select ng-model="interpreters_id">
<option ng-repeat="x in interpreters" value="{{x.id}}" ng-selected="{{x.id == interp_id}}">{{x.first_name}} {{x.middle_name}} {{x.last_name}}</option>
</select>
When I go to view it in my browser it looks like:
but when I inspect the element it shows that option ng-selected is True.
what am I doing wrong?
ngOptions is the recommended way to use select elements in Angular.
Also, if you look at the ngSelected documentation there is a yellow box that states that it does not work properly with the select and ngModel properties which is, in a way, what you are trying to do.
ngRepeat will gladly repeat your option elements however it is not the correct way to work with a select element.
I have prepared a fiddle for you to try it out.
<div ng-app="ngOptionsApp">
<div ng-controller="ExampleController">
<select ng-model="selectedInterpreter" ng-options="interpreter as interpreter.name for interpreter in interpreters track by interpreter.id">
<option value="">Select an Interpreter</option>
</select>
{{selectedInterpreter}}
</div>
</div>
angular.module('ngOptionsApp', []).controller('ExampleController', ['$scope', function($scope) {
$scope.interpreters=[{id: 1, name:'Gill Bates'}, {id: 2, name:'Cohn Jarmack'}, {id: 3, name:'Melon Musk'}];
$scope.selectedInterpreter = $scope.interpreters[0];
}]);
Hope it helps ;)
You should not use the curly braces in ng-selected directive. May you try this?
<option ng-repeat="x in interpreters" value="{{x.id}}" ng-selected="x.id == interp_id">{{x.first_name}} {{x.middle_name}} {{x.last_name}}</option>
http://jsfiddle.net/endrcn/44j19ngp/

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

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

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>

Access Angular Model Validation Without A Form

I'm looking to do use some of the validation features in an Angular Directive that I am building up. However, the directive may or may not be inside of a form. Is there a way to access the validation status of a model without trying to access the state of a form?
My template is along the lines of....
<select id="{{$id}}key" ng-model="newItem.key"
ng-options="key as key.label for key in tableKeys" required>
</select>
<span class="error" ng-show="newItem.key.$error.required">Required!</span>
<input id="{{$id}}value" type="text" ng-model="form.newItem.value" required/>
<span class="error" ng-show="newItem.value.$error.required">Required!</span>
<button ng-click="addItem()">Add Item</button>
(Not seeing any validation messages here)
On top of it, I want to addItem to check the state of validation as well
$scope.addItem = function(){
if(<do something to check validation>)
{
<do some other thing>
}
Any help would be much appreciated!
Thanks,
Andrew
My understanding is that you want to avoid using the form.xyz.$error attributes for error checking.
I do not know how to do it using a directive, but I do know how to do it using the controller.
In that case, you can use the $scope.$watch function on your model.
It would be something like this:-
1.) In your controller,
$scope.$watch('newItem.key',function(){
if( <condition to validate> ==true)
{
$scope.selectError ="errorMessage";
}
});
2.) In your HTML
<select id="{{$id}}key" ng-model="newItem.key"
ng-options="key as key.label for key in tableKeys" required>
</select>
<span class="error" ng-show="selectError">{{selectError}}</span>
Note: This is only for the select element. You can bind the text input to a model, and do the same for it as well.
The $scope.$watch function will watch out for any changes to the specified model, and will execute the accompanying code whenever any change occurs.

Deep linking with <select>, angular js

I want to enable deep linking with the select element
<select ng-model="query">
<option ng-repeat="product in products">{{product.code}}</option>
</select>
So when I choose something, I want the url to change to app/productcode
Any ideas?
You should change your select to:
<select ng-model="query" ng-options="product.code for product in products"></select>
In your controller, you'll use the $location service to change to the route you want via a watch. Something along the lines of:
$scope.$watch('query', function() {
$location.path('/some/route/' + query);
});

Resources