Default Value for Select with ng-options - angularjs

jsFiddle: http://jsfiddle.net/shandylion/2r3z1uma/
I need to display a list of objects as a list of dropdowns, where changing a dropdown changes the corresponding element in the list. Ideally, each dropdown should default to that element.
So, with the following data:
$scope.allPeople = [{"name":"Ann", "Age":10},
{"name":"Barb", "Age":20},
{"name":"Carl", "Age":30}];
$scope.selectedPeople = [{"name":"Ann", "Age":10},
{"name":"Carl", "Age":30}];
and the following HTML:
<div ng-repeat="selectedPerson in selectedPeople">
<select ng-options="person as person.name for person in allPeople"
ng-model="selectedPeople[$index]"
name="select-{{$index}}" id="select-{{$index}}"></select>
</div>
there should be two dropdowns, with the first defaulting to "Ann" and the second to "Carl".
I've tried using ng-selected, but that only seems to work with <option> tags, not inside a <select>. Other Stack Overflow posts suggest we should always use ng-options and never an <option> with an ng-repeat, so I'm stuck as to how to get this to default to the appropriate value.

Here's a sample plunker, which has a working solution as well as the faulty one described below.
The pitfall with dropdowns is that when you want to preselect a value from a list of options, the selected model should be a reference pointing to the same object from the bound list. Say you have:
var list = [{ id: 1, value: 'first'}];
var model = { id: 1, value: 'first' };
<select ng-options="item.value for item in list" ng-model="model"></select>
This will not preselect the dropdown, because list[0] and model are not the same object, although they look alike. If you set ng-model to list[0] it should be preselected just fine.

Since you're using person.name for person in allPeople, the selected option returns person.name as value. You're presetting your $scope.selectedPeople array's values as objects, which does not match with what your select list will return, and hence your initial values are not set properly.
If you want to have person.name as the value of each option, you should change your $scope.selectedPeople to this:
$scope.selectedPeople = ["Ann", "Carl"];
On the other hand if you want to return person as the value of each option, change your ng-options expression to person as person.name for person in allPeople, which means you return person and show it as person.name for each person in $scope.allPeople.

Related

AngularJS ngOptions track by does not set entire object to ngModel

Here my json object :
$scope.todos = [{
name: 'angular',
field: ['a', 'b', 'c', 'd'],
id: 1
}, {
name: 'asd',
field: ['a', 'b', 'c', 'd', 'e'],
id: 2
}];
I give select as :
<select ng-model="dashboard.type" ng-options="item as item.name for item in todos track by item.name"></select>
Now when an option is chosen i want another select which iterates upon ngModel of previous select. The next looks like :
<select ng-model="dashboard.label" ng-options="item as item for item in dashboard.type.field"></select>
It works fine when i choose the option manually but when their is a value in dashboard.type (eg: $scope.dashboard.type.name = 'qwe') in my script, it uses track by to choose the option and save it in dashboard.type, instead of saving the entire object it just saves the value used in track by option.
Value for dashboard.type:
when i choose option manually :
{"name":"qwe","field":["a","b","c","d","f"],"id":3}
When track by is used :
{"name":"qwe"}
NOTE: I cannot use track by item . It has to be a property of the object item. It can either be name or id.
Here's a plnkr.
Edit :
As pointed out by many, i would like to clarify that I can not initialise the object to any value of todos list. This is because dashboard.type.name value would be different every single time and todos list vary from 10 to 100's of objects. Now I have to iterate the list todos check if todos[index].name==someName and assign the relevant object. I am actively trying to avoid this soution (because there has to be a better way).
NOTE : I also tried using ng-change and assign the actual object to dashboard.type.name but that works only when option is selected manually ,which already seems to be working fine. It does not assign the object when track by is used.
IMPORTANT: $scope.dashboard.type.name = 'qwe' is just an example. Value of $scope.dashboard.type.name may change every single time the page is loaded.
PS: Also i should have mentioned this earlier.Sorry, My bad!
This issue is not because of track by. Setting a default value by doing $scope.dashboard.type.name = 'qwe', causes ng-model to look like $scope.dashboard.type = {name : 'qwe'}. Instead of selecting the default value this way, you should use $scope.dashboard.type = $scope.todos[2];. This will make sure the entire object is set to $scope.dashboard.type.
Edited plunker
To initialize the modal by a default value you can use ng-init. For example
<select ng-init="dashboard.type = todos[2]" ng-model="dashboard.type" ng-options="item as item.name for item in todos track by item.name">
</select>
call this function on ng-init
in html
ng-init ="initialize();"
in js
$scope.dashboard={};//initialize object
$scope.dashboard.type ={}//initialize object
$scope.initialize =function(){
//no need to iterate if it is certain that your Id and index is always same suppose your initial id is 3
//then
var currId =3;//suppose initial id is there
$scope.dashboard.type =$scope.todos[currId]
}
here is codepen for it
http://codepen.io/vkvicky-vasudev/pen/MeexmK

Globally Set All Select Boxes to First Available option in AngularJS

I have a lot of select boxes in my application, being generated by lists of data and assigned to various ng-models.
I want to set the ng-model value to the first available option (respecting filters) of all select inputs globally in the app.
So for example a select input like this:
<select ng-model="entry.employee">
<option ng-value="employee.name" ng-repeat="employee in employees | filter:active">{{employee.name}}</option>
</select>
The entry.employee ng-model defaults to null, I need every select box to never be null but always select the first valid option of a select input by default.
It needs to be global as well and be generic enough to work with any type of select input.
Here is the data:
$scope.employees= [
{'name':'Bill'},
{'name':'Frank'},
{'name':'Ted'},
];
Instead of using ng-repeat on option elements use directly ng-option on select tag.
for example
<select class="form-control" ng-options="item.name for item in employees track by item.id" ng-model="selectedItem"></select>
in you controller use:
$scope.selectedItem=$scope.employees[0];
your object would be like:
$scope.employees= [
{id:'1','name':'Bill'},
{id:'2','name':'Frank'},
{id:'3','name':'Ted'},
];
In this case let you select tags be 'n' numbers but whenever you want you ng-model to be the first one just initialize it with the first element in your Object.
Also there is a good thing using ng-option is whenever you want to change the value of the select element at runtime you just need to update the selectedItem element.
Hope this resolves your query

dependent ng-models inputbox and select Angular js

I am having one text box and one dropdown.
I want filtering in ng-repeat section based on both of the above control.
Means if i select name in dropdown and in text box as I typing the filtering should work based on name
and if in dropdown if i select EployeeID then filtering should be work based on Employee.
<input id="txtSearchText" ng-model="searchText"/>
<select>
<option>name</option>
<option>EmployeeID</option>
</select>
<div ng-repeat="u in users">
name : {{u.name}} || EID: {{u.eid}} :
<!-- here i want result -->
</div>
The link that domakas directed you to above should help, but the example is slightly different since it filters using 3 different text input boxes.
You are missing a few things here. The first thing is you need to apply a filter to in the ng-repeat for the users div.
<div ng-repeat="u in users | searchText">
The problem that you run into here, which I am sure you are aware of is that it will filter on all of the values in the users array. You seem to want to only filter on the value in the users array that the dropdown has specified. This means we will have to tie the filter to the dropdown in some fashion to make it dynamic.
The way I would do this is to make the filter an object and not just pure text.
$scope.searchText = {name: '', eid: ''};
Now you need to have the model of your input box tied to this object, but where it stores the value needs to be dynamic based on what the value of the dropdown
<input id="txtSearchText" ng-model="searchText[filter]" />
<select ng-model="filter">
<option value="name" selected>name</option>
<option value="eid">EmployeeID</option>
</select>
The above code will store the value of the dropdown in the correct value of the searchText object. This means that the filter will now use this object to filter out the results in the users div instead of just a string, which it would compare to the full JSON object.
Edit:
Added a watch on the 'searchText' object to clear the other value if the dropdown is switched. Without this the old filter value was still in the 'searchText' object, which caused it to filter on both values.
$scope.$watch('filter', function() {
if($scope.filter == "eid") {
$scope.searchText.name = '';
} else {
$scope.searchText.eid = '';
}
});
Here is a JSFiddle with a working example:
http://jsfiddle.net/glandrum101/NM5A5/1/

Can't get Angular-xeditable Editable-Select to Select the current item when it is bound to a nested JSON object

I can't get the Angular-xeditable Editable-Select to Select the current item when it is bound to a nested JSON object. Data all saves fine, but it just doesn't show up the currently selected item in the Select box, which is driving me nuts, as I am sure I am missing something obvious. I have created a JSFiddle here:
http://jsfiddle.net/NfPcH/1031/
This is the code:
<span editable-select="data.organisation.OrganisationType"
e-ng-options="type.Name for type in data.types">
{{data.organisation.OrganisationType.Name}}
</span>
These are the 2 data objects:
$scope.data.organisation = {
"Id":1,
"Name":"My Organisation",
"OrganisationType":{"Id":2,"Name":"Internal"}
}
$scope.data.types = [
{"Id":1,"Name":"Client"},
{"Id":2,"Name":"Internal"},
{"Id":3,"Name":"Cold"}
]
It works fine when I bind it to the ID within the Nested Object, but then it only changes the Id in my nested object, and I then have to manually filter and change the Name part of the object, which works, but I am sure there must be a better way.
When the item is selected $data is loaded with the id of the item selected. You can use this to retrieve the value after the selection is made.
<span editable-select="data.organisation.OrganisationType"
e-ng-options="type.Name for type in data.types">
{{ findTypeName($data) || data.organisation.OrganisationType.Name}}
</span>
You can then define findTypeName in your controller
$scope.findTypeName = function(id) {
var found = $scope.data.types.filter(function(t){
return (t.Id === id);
});
return found.length ? found[0].Name : null;
};
The trick resides on using the object on the select's ng-options (e.g. 'obj as obj.title') and not a property of the object, so that when an item gets selected, it will assign the whole object to the model and not the property.
The problem with this approach is, that you cannot just compare objects (because comparing an object always compares their reference, not the "contents", so that obj1 == obj2 will never be true, unless they are exact the same object), so the other trick needed here is to use track by <some-id-property> on the ng-options. So your editable would look like this:
<span editable-select="data.organisation.OrganisationType"
e-ng-options="type as type.Name for type in data.types track by type.Id">
{{data.organisation.OrganisationType.Name}}
</span>
Beware that on your JSFiddle you're using a very old version of angular (where track by is not supported), so I created a new one using 1.2, which is the oldest angular version supporting track by:
http://jsfiddle.net/NBhn4/170/

How to bind a model to an option's value

In Angular 1.2.11, given a controller with:
$scope.produce = { 'apples' : [{ 'variety' : 'granny smith', 'price': 2.00}] }
And a view with
<select ng-model='fruits'>
<option value="0">More Fruits...</option>
<option ng-repeat="p.apple for p in produce" value="p">{{ p.variety }}</option>
</select>
How can I bind 'p' to the value attribute? If I try as above the model is bound as a JSON string, not as the model itself (as it would be if I were able to use ng-options).
I'm working around this now by using an ng-change function that uses the value bound to fruits as a lookup in $scope.produce, but this seems like a workaround rather than a solution.
EDIT: Sorry I wasn't more clear about this: I need to be able to hard code 1+ options into the select list, so using ng-options is not a solution.
Here are some fiddles to help illustrate my problem:
** Using ng-options **
ng-options allows for one element that it uses for creating a default option for use as a label. Two problems with this: if I try to use that <option> for its intended purpose I can't add a second option to the select. On the other hand, if I just try to add one <option> element, it gets placed at the top of the <select> list. No good.
** Using ng-repeat **
I'm unable to bind the model to the value attribute of the <option> element. Instead, the value is stringified JSON, which is not bindable.
You need to use ng-options:
<select ng-model='fruits' ng-options="thisFruit.variety in apples">
</select>
If you need to have an option selected as a default (your "More Fruits" option) then you need to add that to the data before it gets to the repeater, and also set your model $scope.fruits = 0 to make that selection selected by default.

Resources