I am getting content of dropdown list as a Map<number, string>. When I get the map, it is received sorted according to keys in ascending order.
While showing it in html, I am setting pipe keyvalue and provided a function to sort the items in ascending order of values.
Now, I am trying to select first element of this dropdown, but unable to do so.
I have tried jQuery method to select the first element.
I have tried to set ngModel of the select box to first value of the map, but it sets the value to the first value received in the Map which is sorted by key.
My HTML:
<select class="form-control" id="empId" [(ngModel)]="empId" [disabled]="!isEditable">
<option *ngFor="let emp of empNames | keyvalue:descOrder" [value]="emp.key">{{ emp.value }}</option>
</select>
My ts file:
this.commonService.getEmployeeList())
.subscribe((response) => {
this.empNames = response;
this.empId = this.empNames.keys().next().value;
});
data I am sending from server is:
{id:1,name: "Tim"},
{id:6,name: "Martha"},
{id:5,name: "Alex"},
{id:8,name: "Stacy"}
data I am receiving on screen is like:
Alex
Martha
Stacy
Tim
with Tim pre-selected
what I need is Alex should be pre-selected.
Then set the empId before subscribing.
this.empId = 5;
this.commonService.getEmployeeList())
.subscribe((response) => {
this.empNames = response;
});
Of course you might want another logic based on some kind of order. You can never be sure how the data are going to be received.
In this case you need to send the order from your api and filter by order.
Working Demo
<option *ngFor="let emp of empNames | keyvalue:descOrder" [value]="emp.key" [selected]="emp.id === 1">{{ emp.value }}</option>
you can use selected attribute like above
I would highly recommand you to use Angular's reactive forms! And set the select's value to the one you want, when you recieve your data. Don't use ngModel as it is deprecated and should have been removed by Angular 7 (Or will be soon). Check this
The best way to pre select an option is to use ngModel as you tried. Your list is sorted by keys so what you want is not to select the first item, yes it's the first but in other order so or you change the order in code or you search for the item you want to select and stores it to set on model.
I would suggest some changes that should improve the code and fix your problem.
<select class="form-control" id="empId" [(ngModel)]="currentEmployer" [disabled]="!isEditable">
<option *ngFor="let emp of employers$ | async" [value]="emp">{{ emp.value }}</option>
</select>
And order your list in a pipe with the function you prefer.
public currentEmployer: Employer = null;
private sortByNameAscending(e1, e2) {
return e1.name > e2.name ? 1 : 0;
}
this.employers$ = this.commonService.getEmployeeList().pipe(
switchMap(employers => {
const sortedList = employers.sort(this.sortByNameAscending);
if (sortedList.length > 0) {
this.currentEmployer = sortedList[0];
}
return sortedList;
})
);
I'm struggling with modifying some code I have that dynamically creates a select box based on column values from a sharepoint list.
at the moment the code:
function getAjaxFilter(name, internalName) {
$.ajax({
url: $().SPServices.SPGetCurrentSite() + '/_layouts/filter.aspx?ListId=' + listID + '&FieldInternalName=' + internalName + '&ViewId=' + viewID + '&FilterOnly=1&Filter=1' + filterFieldsParams,
success: function(data) {
$('#filterField' + internalName).html(name).append($("<div></div>").append(data).find("select"));
//clear current onChange event
$("#diidFilter" + internalName).attr("onchange", '');
// add change event
$("#diidFilter" + internalName).change(function() {
FilterField(viewID, internalName, encodeURIComponent(this.options[this.selectedIndex].value), this.selectedIndex);
});
}
Creates the following html:
<div id="filterFieldSub_Category">
Sub Category
<select title="Filter by Sub_Category" id="diidFilterSub_Category">
<option>(All)</option>
<option>(Empty)</option>
<option value="Test">Test</option>
</select>
What I'm trying to achieve is to get it to produce a select class so I can apply it to a 3rd party selectbox styler like bootstrap select. so It needs to look like:
<select class="selectpicker" id= "filterFieldSub_Category">
<option>(all)</option>
<option>(empty)</option>
<option>test</option>
</select>
I'm not sure where to start, so if anyone could point me in the right direction that would be a huge help :)
You could add the class using addClass() :
$("#diidFilter" + internalName).addClass('selectpicker');
Hope this helps.
I'm using JavaScript to get the selected value of a drop list in MVC 4 but have an issue I think is caused by the HTMLHelper.
CONTROLLER - to populate droplist
private string PopulateStandard(object selectedValue = null)
{
var query = db.Database
.SqlQuery<StandardModel>(
"SELECT * FROM [DBO].[GetStandards] ('" +
User.Identity.Name + "', '" + DateTime.UtcNow + "')")
.ToList();
ViewBag.Standard = new SelectList(query, "Standard", "Standard", selectedValue);
try { return query[0].Standard; }
catch { return ""; }
}
VIEW
The view has this section for the drop list. Please note the inclusion of "All". I think this is the problem. That puts a first row atop the drop list saying "All" with a null value. I want that. So far so good (so what)
#Html.DisplayNameFor(m => m.Standard)
#Html.DropDownList("Standard", "All")
JAVASCRIPT
It's a long story, but I have other code that requires me to get the value of the drop list using JavaScript, so I'm doing it like this:
var e = document.getElementById("Standard");
var sStandard = e.options[e.selectedIndex].value;
PROBLEM
If no value was chosen, then I should get the first row, which would be "All" for text or "" for value. Instead, I'm getting the second row, which is the first one with data as populated from the database.
Is the HTML helper causing me to not get the first row? Or is my JavaScript off?
EDIT - to show ViewSource on drop list
These are the first few lines of the rendered list
<select id="Standard" name="Standard"><option value="">All</option>
<option value="2S">2S</option>
<option value="Aero">Aero</option>
#Html.DropDownList("Standard", "All")
here "All" is option label. so you do not get this as value.
I have read about it in other posts, but I couldn't figure it out.
I have an array,
$scope.items = [
{ID: '000001', Title: 'Chicago'},
{ID: '000002', Title: 'New York'},
{ID: '000003', Title: 'Washington'},
];
I want to render it as:
<select>
<option value="000001">Chicago</option>
<option value="000002">New York</option>
<option value="000003">Washington</option>
</select>
And also I want to select the option with ID=000002.
I have read select and tried, but I can't figure it out.
One thing to note is that ngModel is required for ngOptions to work... note the ng-model="blah" which is saying "set $scope.blah to the selected value".
Try this:
<select ng-model="blah" ng-options="item.ID as item.Title for item in items"></select>
Here's more from AngularJS's documentation (if you haven't seen it):
for array data sources:
label for value in array
select as label for value in array
label group by group for value in array
= select as label group by group for value in array
for object data sources:
label for (key , value) in object
select as label for (key , value) in object
label group by group for (key, value) in object
select as label group by group for (key, value) in object
For some clarification on option tag values in AngularJS:
When you use ng-options, the values of option tags written out by ng-options will always be the index of the array item the option tag relates to. This is because AngularJS actually allows you to select entire objects with select controls, and not just primitive types. For example:
app.controller('MainCtrl', function($scope) {
$scope.items = [
{ id: 1, name: 'foo' },
{ id: 2, name: 'bar' },
{ id: 3, name: 'blah' }
];
});
<div ng-controller="MainCtrl">
<select ng-model="selectedItem" ng-options="item as item.name for item in items"></select>
<pre>{{selectedItem | json}}</pre>
</div>
The above will allow you to select an entire object into $scope.selectedItem directly. The point is, with AngularJS, you don't need to worry about what's in your option tag. Let AngularJS handle that; you should only care about what's in your model in your scope.
Here is a plunker demonstrating the behavior above, and showing the HTML written out
Dealing with the default option:
There are a few things I've failed to mention above relating to the default option.
Selecting the first option and removing the empty option:
You can do this by adding a simple ng-init that sets the model (from ng-model) to the first element in the items your repeating in ng-options:
<select ng-init="foo = foo || items[0]" ng-model="foo" ng-options="item as item.name for item in items"></select>
Note: This could get a little crazy if foo happens to be initialized properly to something "falsy". In that case, you'll want to handle the initialization of foo in your controller, most likely.
Customizing the default option:
This is a little different; here all you need to do is add an option tag as a child of your select, with an empty value attribute, then customize its inner text:
<select ng-model="foo" ng-options="item as item.name for item in items">
<option value="">Nothing selected</option>
</select>
Note: In this case the "empty" option will stay there even after you select a different option. This isn't the case for the default behavior of selects under AngularJS.
A customized default option that hides after a selection is made:
If you wanted your customized default option to go away after you select a value, you can add an ng-hide attribute to your default option:
<select ng-model="foo" ng-options="item as item.name for item in items">
<option value="" ng-if="foo">Select something to remove me.</option>
</select>
I'm learning AngularJS and was struggling with selection as well. I know this question is already answered, but I wanted to share some more code nevertheless.
In my test I have two listboxes: car makes and car models. The models list is disabled until some make is selected. If selection in makes listbox is later reset (set to 'Select Make') then the models listbox becomes disabled again AND its selection is reset as well (to 'Select Model'). Makes are retrieved as a resource while models are just hard-coded.
Makes JSON:
[
{"code": "0", "name": "Select Make"},
{"code": "1", "name": "Acura"},
{"code": "2", "name": "Audi"}
]
services.js:
angular.module('makeServices', ['ngResource']).
factory('Make', function($resource){
return $resource('makes.json', {}, {
query: {method:'GET', isArray:true}
});
});
HTML file:
<div ng:controller="MakeModelCtrl">
<div>Make</div>
<select id="makeListBox"
ng-model="make.selected"
ng-options="make.code as make.name for make in makes"
ng-change="makeChanged(make.selected)">
</select>
<div>Model</div>
<select id="modelListBox"
ng-disabled="makeNotSelected"
ng-model="model.selected"
ng-options="model.code as model.name for model in models">
</select>
</div>
controllers.js:
function MakeModelCtrl($scope)
{
$scope.makeNotSelected = true;
$scope.make = {selected: "0"};
$scope.makes = Make.query({}, function (makes) {
$scope.make = {selected: makes[0].code};
});
$scope.makeChanged = function(selectedMakeCode) {
$scope.makeNotSelected = !selectedMakeCode;
if ($scope.makeNotSelected)
{
$scope.model = {selected: "0"};
}
};
$scope.models = [
{code:"0", name:"Select Model"},
{code:"1", name:"Model1"},
{code:"2", name:"Model2"}
];
$scope.model = {selected: "0"};
}
For some reason AngularJS allows to get me confused. Their documentation is pretty horrible on this. More good examples of variations would be welcome.
Anyway, I have a slight variation on Ben Lesh's answer.
My data collections looks like this:
items =
[
{ key:"AD",value:"Andorra" }
, { key:"AI",value:"Anguilla" }
, { key:"AO",value:"Angola" }
...etc..
]
Now
<select ng-model="countries" ng-options="item.key as item.value for item in items"></select>
still resulted in the options value to be the index (0, 1, 2, etc.).
Adding Track By fixed it for me:
<select ng-model="blah" ng-options="item.value for item in items track by item.key"></select>
I reckon it happens more often that you want to add an array of objects into an select list, so I am going to remember this one!
Be aware that from AngularJS 1.4 you can't use ng-options any more, but you need to use ng-repeat on your option tag:
<select name="test">
<option ng-repeat="item in items" value="{{item.key}}">{{item.value}}</option>
</select>
The question is already answered (BTW, really good and comprehensive answer provided by Ben), but I would like to add another element for completeness, which may be also very handy.
In the example suggested by Ben:
<select ng-model="blah" ng-options="item.ID as item.Title for item in items"></select>
the following ngOptions form has been used: select as label for value in array.
Label is an expression, which result will be the label for <option> element. In that case you can perform certain string concatenations, in order to have more complex option labels.
Examples:
ng-options="item.ID as item.Title + ' - ' + item.ID for item in items" gives you labels like Title - ID
ng-options="item.ID as item.Title + ' (' + item.Title.length + ')' for item in items" gives you labels like Title (X), where X is length of Title string.
You can also use filters, for example,
ng-options="item.ID as item.Title + ' (' + (item.Title | uppercase) + ')' for item in items" gives you labels like Title (TITLE), where Title value of Title property and TITLE is the same value but converted to uppercase characters.
ng-options="item.ID as item.Title + ' (' + (item.SomeDate | date) + ')' for item in items" gives you labels like Title (27 Sep 2015), if your model has a property SomeDate
In CoffeeScript:
#directive
app.directive('select2', ->
templateUrl: 'partials/select.html'
restrict: 'E'
transclude: 1
replace: 1
scope:
options: '='
model: '='
link: (scope, el, atr)->
el.bind 'change', ->
console.log this.value
scope.model = parseInt(this.value)
console.log scope
scope.$apply()
)
<!-- HTML partial -->
<select>
<option ng-repeat='o in options'
value='{{$index}}' ng-bind='o'></option>
</select>
<!-- HTML usage -->
<select2 options='mnuOffline' model='offlinePage.toggle' ></select2>
<!-- Conclusion -->
<p>Sometimes it's much easier to create your own directive...</p>
If you need a custom title for each option, ng-options is not applicable. Instead use ng-repeat with options:
<select ng-model="myVariable">
<option ng-repeat="item in items"
value="{{item.ID}}"
title="Custom title: {{item.Title}} [{{item.ID}}]">
{{item.Title}}
</option>
</select>
It can be useful. Bindings do not always work.
<select id="product" class="form-control" name="product" required
ng-model="issue.productId"
ng-change="getProductVersions()"
ng-options="p.id as p.shortName for p in products"></select>
For example, you fill the options list source model from a REST service. A selected value was known before filling the list, and it was set. After executing the REST request with $http, the list option is done.
But the selected option is not set. For unknown reasons AngularJS in shadow $digest executing does not bind selected as it should be. I have got to use jQuery to set the selected. It`s important! AngularJS, in shadow, adds the prefix to the value of the attr "value" for generated by ng-repeat options. For int it is "number:".
$scope.issue.productId = productId;
function activate() {
$http.get('/product/list')
.then(function (response) {
$scope.products = response.data;
if (productId) {
console.log("" + $("#product option").length);//for clarity
$timeout(function () {
console.log("" + $("#product option").length);//for clarity
$('#product').val('number:'+productId);
}, 200);
}
});
}
A while ago I posted this question asking how to get JSON data into jQuery dropdowns
jquery dropdown from mysql based on previous selection
Well the people here were awesome and I got a solution. The problem I'm having now is that the suggest solution dosen't work in my production enviorment but it does in my test.
In order to prevent duplicate entrees I am using jQuery empty() the problem is that using empty() seems to also be preventing me from selecting the first option.
this is the function that is generating the optiosn from JSON
function(data){
var select = $('[name="employee_manager"]');
select.empty();
select.append(new Option(ucfirst('No Manager'),'100'));
$.each(data, function(index, array) {
select.append(new Option(ucfirst(array['first_name'])+ " "+ucfirst(array['last_name']),array['id']));
});
Is that an alternative to empty() that won't prevent selection?
EDIT This seems to only be a problem if there are fewer than two items being dynamically input
EDIT 2 Here is the HTML. It seems that I can't select the first option if empty() is present
<label for="manager">Reports To</label>
<select name="employee_manager">
<option value="1">Please Select Employee Role</option>
<option value="2">John Doe</option>
<option value="3">James Smith</option>
</select>
EDIT 3
Looks like the empty class is adding a span to my select
<div class="selector">
<span style="-moz-user-select: none;">Jane Smith</span>
<select name="employee_manager" style="opacity: 0;">
<option value="100">No Manager</option>
</select>
</div>
EDIT 4
Okay so here is a jsfiddle that shows the problem. I couldn't get the JSON data to load correctly but you can still see the problem if you attempt to click on the first item in the list. It seems that it's a problem with uniformjs as if uniform is removed it's not a problem
http://jsfiddle.net/BandonRandon/xXUfp/1/
Don't use empty() to clear the options of drop down list. It's wrong, because it should be used to remove DOM children.
Instead use such code:
$("select[name='employee_manager'] > option").remove();
Edit: when using the jQuery uniform plugin, dynamically adding options is messing things up... one way around that does not require to go and try fix the plugin is to always have enough "dummy" options in place (e.g. 20 if that's the max amount of options) then change the text/value of those options and hide all others according to your data.
The proper JS code will now look like this:
var myData = [];
myData.push( { text: "Please Select A Manager (JS)", value: "null" } );
myData.push( { text: "No Manager", value: "100" } );
myData.push( { text: ucfirst("a third choice"), value: "42" } );
$.each(data, function(index, array) {
myData.push( { text: ucfirst(array['first_name'])+ " " + ucfirst(array['last_name']), value: array['id'] } );
});
$("select[name='employee_manager'] > option").each(function(index) {
if (index < myData.length) {
$(this).text(myData[index]["text"]);
$(this).val(myData[index]["value"]);
$(this).show();
}
else {
$(this).hide();
}
});
Updated jsFiddle.
Crude, but working.... :)
Well try something like this, but no guaranteed
$('<option></option>').val(100).html('No Manager').appendTo($(select));
$.each(data, function(index, array) {
$('<option></option>').val(array['id']).html(ucfirst(array['first_name'])+ " "+ucfirst(array['last_name']).appendTo($(select));
});