AngularJS select: remove empty option and use data objects not arrays - angularjs

I've been searching high and low for an explanation as to how to remove the empty option AngularJS always renders in selects. I have found lots of information doing this when the options are derived from a JSON array placed directly in the code, but I can't find anything about removing this empty option when working with data objects.
Say I have object "foo" in my database and "foo" has both a "name" and a "bar_id".
Can someone toss me a clue about doing this with data objects?
References:
Angular JS Remove Blank option from Select Option
http://jsfiddle.net/MTfRD/3/ (This is someone else's fiddle from the SO question linked above; code is not mine but taken from that fiddle.)
JS:
function MyCtrl($scope) {
$scope.typeOptions = [
{ name: 'Feature', value: 'feature' },
{ name: 'Bug', value: 'bug' },
{ name: 'Enhancement', value: 'enhancement' }
];
$scope.form = {type : $scope.typeOptions[0].value};
}
I want to get foo.name and foo.bar_id. I want foo.name to be the option label and foo.bar_id to be the value (e.g. <option value="foo.bar_id">foo.name</option>. For each foo, foo.bar_id will then become an identifying parameter in the record to pull up and display "on change" (immediately upon selection of the option).
I've tried everything I can think of to set this up and nothing seems to work. Worst of all it either fails silently, leaving me with no indication what I am doing wrong, or complains that foo is not an object, which frustrates me to no end. (I assure you, "foo" IS being loaded by an AJAX request in the actual code I'm working on and works fine as an object everywhere else -- NDAs prohibit me from sharing actual code though, sorry.)
Using the above example from the other thread, I understand I would assign something like ng-model="typeOptions" in the select tag within the template, but how would I get "typeOptions" to access foo and make foo.name the option label and foo.bar_id the option value? Also, default angular values for the options (the ones that look like a generated index) are fine with me, but I still need to call upon foo.bar_id to get the task done, so it has to be "in there somewhere".
Any help would be appreciated; currently I'm stuck with the hackish ng-repeat in the option itself, which I understand is not best practice.. Also I'm still fairly new at Angular, and still find it somewhat confusing, so the simpler and more straightforward your answers, the better I will be able to use them successfully. Thanks!

update
Ok, I just now understood what your real question was (at least I hope so ;)). And fortunately this is very easy:
Ctrl:
$scope.options = {
a: 1,
b: 2,
c: 3
};
$scope.selected = 1;
View:
<select
data-ng-model="selected"
data-ng-options="v as k for (k, v) in options"
></select>
Demo: http://jsbin.com/hufehidotuca/1/
for more options, have a look at the manual. Especially under:
ngOptions (optional) ยป for object data sources:
previous answer:
As I wrote in the comments, with ngOptions:
you can't force angular to use your model-data as the actual option-value in the view. Angular handles this in it's own way. It only assures that your scope-model will be set to the correct value on change. If that's not what you want, then you'll have to write your own directive, probably using ngRepeat.
you'll always need two seperate models. One which acts as the list of options (this should probably always be an array of objects) and one to store the selected value (this will then differ in regards to how you set up the ngOptions directive).
Hint: The notorious blank options is always the result when angular can't match the assigned ngModel to the list of options and no real blank option is setup. (Note: if the ngModel is just undefined in the current scope or it's value can't be matched against the list of options, then it will be set or it's value will be overridden, with the first selection of any option. This is why the blank option disappears afterwards.)
Ctrl:
// the "list of options"
$scope.options = [
{ name: 'A', id: 1 },
{ name: 'B', id: 2 },
{ name: 'C', id: 3 },
{ name: 'D', id: 4 }
];
// a pre-selection by value
$scope.asValue = 2;
// a pre-selection by object-identity
$scope.asObject = $scope.options[3];
View:
<!-- select as value -->
<select
data-ng-model="asValue"
data-ng-options="foo.id as foo.name for foo in options"
></select>
<!-- select as object -->
<select
data-ng-model="asObject"
data-ng-options="foo as foo.name for foo in options"
></select>
<!-- the notorious blank option -->
<select
data-ng-model="asBogus"
data-ng-options="foo as foo.name for foo in options"
></select>
<!-- blank option correctly set up -->
<select
data-ng-model="asBogus"
data-ng-options="foo as foo.name for foo in options"
>
<option value="">Please select</option>
</select>
demo:
http://jsbin.com/yasodacomadu/1/

Just posting as a follow up to the whole data object issue ...
To make this work, I had to get the ng-options properly designated first of all. I've mentioned elsewhere that one of my recurring personal issues learning AngularJS is "overthinking" things and confusing myself unnecessarily, and this was no exception. After conferring with a co-worker who is scripting the controller on this app, using my "foo.bar" pseudo-designations, this is how I needed to set up the HTML template:
<select ng-model="selected_item" ng-options="bar.item_name for bar in foo.bars">
I wanted this select to be set to the "bar" of the current display (as opposed to the first indexed "bar" in the complete list of "bars" this "foo" has), so I had to locate the place in the app controller where this data object is being passed in and add for the model (which I will call $selected_item):
$scope.selected_item = _.find($scope.foo.bars, function(bar) {
return bar.item_id == $scope.current_result.foo_item_id;
});
It's a pretty complicated data structure with a lot of stored procedures and concatenated tables, so my bad for not being able to translate it easily into a working pseudo-object/properties example. Yoshi you have been very helpful; the gaps in communication here have all been my baddies. Thank you for sticking with me.
For other confused AngularJS n00bs who might stumble upon this thread: the place I was "overthinking" it and confusing myself was by mistakenly believing that I needed some sort of code in place of the JSON arrays the many examples I studied, to pass in the data object. That is incorrect -- "nothing" needs to go there with regard to passing in a data object and/or its properties. The data object's properties are passed directly into the template, within the select tag itself, using ng-options. So if anyone else finds themselves stumped by this, you're probably making the same two mistakes I made: (1) thinking "something else" should replace the JSON arrays examples online are using and (2) your ng-options are not written correctly.
Angular sure makes me feel stupid sometimes!! It's fun and challenging but sometimes it just leaves me feeling like an idiot. :-)

<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>

While Using Css we removing the Empty Option like
<option value="?undefind"></option>
So While Usiing Css we can remove the emptyy Options.
Shown in this fiddle
http://jsfiddle.net/KN9xx/1060/

Related

ng-repeat in select tag not producing results

Having a lot of trouble with ng-repeat in a select tag. The below is not working for some reason though all documentation indicates that it should.
<select id="blahh" ng-model="log_instances" class="selectpicker" multiple>
<option>this works</option> <!-- this works -->
<option ng-repeat="comp in env.status.components">test-value</option>
</select>
The only option that ends up showing is the 'this works' one, but I would expect 'test-value' to show up for each of the items described in the ng-repeat's.
Additionally, I also checked the console for angular.element(document.getElementById('blahh')).scope() and it shows the proper data that I would expect to see. Also, if I include a table right below this select with the same ng-repeat's and fields, it produces the expected output just fine. I'm using Angular 1.6.5
Any help is appreciated!
The HTML snippet included with the original question had <span> tags as immediate children of the <select> tag, which would've produced invalid markup as only <option> or <optgroup> elements are permitted.
Whenever you have a data collection that needs to be presented as a select list, Angular's ng-options attribute makes it easy.
DEMO
Also, if you need a default option (for when the collection data might be in transit due to an AJAX request), include an <option> element assigned with an empty value (i.e. value=""), then you could use ng-if to hide this default option when it is no longer necessary.
Use ng-options like below. But your code also should work check env.status.components
<select ng-options="item as item.label for item in items track by item.id" ng-model="selected"></select>
My question to you would be, why do you want to use a ng-repeat inside a multiple select, when you have ng-options handy?
Assuming your comp object looks like this:
{
name: 'somevalue'
}
I would change your code to look like so:
<select id="blahh" multiple="true" ng-model="log_instances" ng-options="comp.name for comp in env.status.components"></select>
Please have a look at the plunker demo I have made for you

AngularJS Multiple Select not showing preselected options

I have been most part of the morning working on a solution for when I need to assign several values to an entity on my form.
So, the idea is I have an Entity called QualityData and this entity can have different MechanismIdentifiers.
Best solution I thought of, use a multiple select.
All works fine combining both these solutions:
AngularJS selecting multiple options
Get value when selected ng-option changes
I can access the array of selected options, assign it to my entity, etc... But I have a "minor" fallback, which is that I can't get the preselected options (the ones that would come from the server when loading data for editing) to be highlighted in the select field when using a dynamic approach such as <option ng-repeat> or ng-options, it will only work when hardcoding the options. Another bug is that if I wish to add more values than those that are in the preselected array, it will erase all values present in it when using a dynamic approach, working fine when harcoding.
The markup:
<select multiple ng-change="showAlert(selectedValues)" ng-model="selectedValues">
<!--ng-options="resDatasIdOfMechanism as resDatasIdOfMechanism.name for resDatasIdOfMechanism in resDatasIdOfMechanisms track by resDatasIdOfMechanism.id" value="resDatasIdOfMechanism.id">-->
<option value="1">{{resDatasIdOfMechanisms[0].name}}</option>
<option value="2">{{resDatasIdOfMechanisms[1].name}}</option>
<option value="3">{{resDatasIdOfMechanisms[2].name}}</option>
</select>
If I try to use the line that is commented, it's when the marked option will not work
The controller:
$scope.selectedAlready = [{id:1, name:"Based on Antibiogram"}];
$scope.selectedMechanisms=[];
$scope.resDatasIdOfMechanisms = [{id:1,name:"Based on Antibiogram"}, {id:2,name:"Molecular"}, {id:3,name:"Genetic"}];
$scope.selected = $scope.selectedAlready;
$scope.selectedValues = [];
$scope.$watch('selected', function(nowSelected){
$scope.selectedValues = [];
if( ! nowSelected ){
return;
}
angular.forEach(nowSelected, function(val){
$scope.selectedValues.push( val.id.toString());
console.log("look");
});
});
$scope.showAlert=function(listOfMultipleChoices){
//alert(object);
}
EDIT to add jsfiddle link which is working but I still haven't found solution to original question: https://jsfiddle.net/StevenEvenSteven/ybapx09w/
There is a typo in your code.
Add a comma after '$scope' in your controller definition
fiddleApp.controller('myFiddle', ['$scope', function($scope) {
I've forked your jsfiddle and it is working as you expected.

Adding angular directives to simple_form in rails breaks selected option for collection input

Not sure if there's a workaround for this, I'm doing something wrong, or this is a collision between simple form or angular, but:
.field
= f.input :role, collection: roles.map(&:name), selected: user.role.try(:name), include_blank: 'Select', required: true, input_html: { "ng-model" => "role" }
renders (which looks correct):
<select ng-model="role" class="select required" name="user[role]" id="user_role">
<option value="">Select</option>
<option value="system">system</option>
<option selected="selected" value="fcm">fcm</option>
<option value="regulatory">regulatory</option>
<option value="operations">operations</option>
<option value="help_desk">help_desk</option>
</select>
But the selected value is the include_blank value of 'Select'. And yes, role is set on the user.
The reason it's doing this is because of the way angular models work and it requires an understanding of this. Essentially the ruby generates the select correctly choosing the selected option of the select box too.
However, once the angular is loaded and sees ng-model on this select it sets the current selected option to the value of the model, in your case, role.
Thus if you want to have an angular model for this select, you need to set the initial value of that model.
Try the following:
.field
= f.input :role, collection: roles.map(&:name), include_blank: 'Select', required: true, input_html: { "ng-model" => "role", "ng-init" => "role = #{user.role.try(:name)}" }
Note that the selected option has been removed entirely since this will be controlled by the Angular model, which is initialized to that value using ruby string interpolation.
I thought for a moment on this particular example and I am not quite sure what you expected to happen with the result.
Although, I assumed that you want to have option with attribute selected="selected" selected as a default value, instead of value="", which is only a blank field. If that I understood correctly and this is the point, that means there are several fields, which might be incorrect and We (the community) do not know how you completed them, but I think I dug up for the problem... ;)
Angular directive - At first, I do not know which version of angular you used in the example (I assume 1.X, because question have 6 months from this moment). The AngularJS select directive overrides the default behavior of select element and change it a bit.
I prepared a simple example with Angular v1.0.1 for the tests and it looks behave correctly in few aspects. If you use ng-model="role" and set the role to fcm (String), like $scope.role = 'fcm', the angular is obligate to set this value if it will find it.
I have also tested (AngularJS v1.0.1) what if the role is not set (undefined), then angular also point on empty string value like value="" and it not see into attribute selected and not set it as default. In the other side, the latest stable AngularJS v1.5.6 does support selected attribute example with AngularJS v1.5.6, so it might be the core of the problem.
Well, the solution for this is simple:
upgrade AngularJS for the latest 1.X version or
consider to use
ngSelected
or ngInit/SO
solution instead if the version AngularJS you used support that.

populate a select with ng-grid columns

I've got an ng-grid that I want to be able to search on particular columns. The user enters some text and chooses a column from a dropdown. My UX guy doesn't much fancy the search-field-in-every-column-header that ng-grid supports.
Here is my Plunker:
http://plnkr.co/edit/WofBDA6QQkCDcwDMznzf?p=preview
(I haven't bothered with the text field yet, just worried about the field picker so far)
I've got a method that grabs the field and displayName for each field and populates my select with options, but for some reason, it gives me an empty first option. I don't want an empty one - and certainly not if it's going to look like this:
<option value="? undefined:undefined ?"></option>
I want it to default to a field of my choice (in the plunker example, I want it to default to 'age')
I can't figure out why I'm getting an undefined option - unless it's because the control is being rendered by my getFilterFields() function BEFORE the colDefs are fully defined. I've tried various ways of delaying the getFilterFields()function - I played with init: gridInit parameter, but so far, no joy.
How can I assure that
1] my dropdown contains ONLY valid columns, and
2] one of them is preselected?
It's better to use ng-options and set the model to the option that you want to be selected.
<select ng-model="selectedItem"
ng-options="item.value as item.name for item in filterOptions.filterFields">
</select>
and in the controller, set:
$scope.selectedItem = "age"; // equal to the value of the default option

ng-model and ng-options not matching up?

I have a method in my resources object that comes in as:
resources.type
otherstuff: 'more strings'
type:'specifictype'
morestuff: 'morestuff'
The user can change this type with a dropdown / through another call that gets a list of all possible types which looks like resourceList.types which has a list of objects like this json
types:
[
{name:'resourcetype1'},
{name:'resourcetype2'},
etc...
],
my html looks like:
<select ng-model="resources.type" ng-options="name.name for name in resourceList.types">
</select>
The select/drop down box populates with my resourceList.type stuff but when the page loads the ng-model doesn't set to the already selected resource type. It actually selects a blank entry at the top of the drop down when you click. Is angular picky about this? How can I get the ng-model to behave the way I want it to?
I tried messing around with ng-options with the different ways of getting the repeat but I feel like this is more how angular connects the model. Does it just match the string to the ng-options list?
Here's the plnkr as you can see it's not defaulting to type1
http://plnkr.co/edit/NyWACtFQuyndR6CG8lpN?p=info
In Angular, the model is the single source of truth.
This means that if you want a value selected (and bound to your ngModel) you need to assign it to the model:
<select ng-model="resources.type"
ng-options="type.name as type.name for type in resourceList.types">
</select>
$scope.resources = {...};
$scope.resourceList = {
...
types: [
{name: 'resourcetype1'},
{name: 'resourcetype2'},
...
]
};
// Set the model to the desired value
$scope.resources.type = $scope.resourceList.types[0].name;
See, also, this short demo.
You don't have to set your model's value to the reference object in resourceList. In fact, the accepted answer works fine without this line:
$scope.resources.type = $scope.resourceList.types[0].name;
How is it working? Thanks to the "as" notation in the ngOptions. Without the "as", the match is made on the full type element, which is an object, so the match is made on the reference's object, not the name's value.
With the "as" the match is made on the element's property, name.
I've forked the plunker: http://plnkr.co/edit/kORfxGdsWBUlFWHXp6Ry?p=preview
in my case it didnt work since ngOptions was an array of integers and i was trying to set ngModal to string type (2the year 2014).
the solution is simple: parseInt function

Resources