So, What I'm trying to do is fairly simple with vanilla JS, but I'm using AngularJS and I would like to know how to do it the best way within the framework. I want to update the selected options in a multiple select box. I do not want to add or remove any of the options. Here is what my HTML looks like:
<select multiple>
<option value="1">Blue</option>
<option value="2">Green</option>
<option value="3">Yellow</option>
<option value="4">Red</option>
</select>
Using the following array, I'd like to programmatically select/deselect options from this list:
[{id:1, name:"Blue"},{id:4, name:"Red"}]
When I set this array in the scope, I want the select box to deselect anything that is not Blue or Red and select Blue and Red. The standard response that I've seen on the Google Groups is to use ng-repeat. However, I can't recreate the list every time because the list of selected values is incomplete. As far as I can tell, AngularJS has no mechanism for this, and I'm at a loss as to how I would do this without resorting to using jQuery.
ngModel is pretty awesome! If you specify the indexes as a model selectedValues
<select multiple ng-model="selectedValues">
built from your list (selected) in a $watch
$scope.$watch('selected', function(nowSelected){
// reset to nothing, could use `splice` to preserve non-angular references
$scope.selectedValues = [];
if( ! nowSelected ){
// sometimes selected is null or undefined
return;
}
// here's the magic
angular.forEach(nowSelected, function(val){
$scope.selectedValues.push( val.id.toString() );
});
});
ngModel will automatically select them for you.
Note that this data binding is one-way (selected to UI). If you're wanting to use the <select> UI to build your list, I'd suggest refactoring the data (or using another $watch but those can be expensive).
Yes, selectedValues needs to contain strings, not numbers. (At least it did for me :)
Full example at http://jsfiddle.net/JB3Un/
Related
This is my Angular 2 Code:
HTML:
<select class="form-control" [(ngModel)]="wrapupData.assignToEmployee">
<option value="" disabled>Choose Status</option>
<option *ngFor="let emp of masterWrapupLov.employeeList"
[value]='emp.id'>{{emp?.name}}</option>
</select>
where wrapupData.assignToEmployee is a string, masterWrapupLov.employeeList is an array of Objects comprising id: string and name: string.
This code works perfectly fine selecting the option to make it reflect in the wrapupData.assignToEmployee model.
What I wanted to achieve is to select a default option when loading the DOM and update the model if the option is changed. I tried using [selected] comparing emp.id with the value I wanted to select, it did work in the UI but is not getting binded with the model as and when I change it. I tried using a default value using the model, that too is not working as it should and is not getting binded after the first default binding. I don't know if I'm clear enough, but I tried many methods that people have already suggested but nothing seems to work.
I'm trying to pre select an option in a select dropdown, I know how to do it if the value for the options are static. But what if they change dynamically? In my case I got a list of albums which updates a lot so I never know what the value of the options will be. I tried selecting the first album in the list by using ng-init like this:
<select class="rounded bold" ng-model="selectedAlbum" ng-init="selectedAlbum='album[0].albumName'">
<option ng-repeat="album in albumsList" value="{{album.albumName}}" ng-bind="album.albumName">
</select>
But with no luck, from my searches I can't really find anything that answers this. It might be ng-options but from what I've seen that doesn't generate options with a binding on them. Like I've done in the code above.
How would I achieve this?
Use the ng-options directive to build you list, and include an option with an empty value:
<select class="rounded bold"
ng-model="selectedAlbum"
ng-options="album.albumName for album in albumsList">
<option value="">-- choose album--</option>
</select>
See this jsBin
In your controller just change the selectedAlbum model to the value you want
$scope.selectedAlbum = albumsList[0].albumName
If albumsList changes, the model (selectedAlbum) may not match any albumName. In this case, selectedAlbum will remain on its previous value, and angular adds an "unknown" option to your select. As I understood your question,in this situation, you want the first item in the new albumList to be selected (which BTW I think is a reasonable action).
In order to achieve this, you can watch albumList and check if selectedAlbum is valid according to new albumList. If not, you can change it to first item:
$scope.$watch("alubmList", function(newAlbumList){
if(angular.isArray(newAlbumList) && newAlbumList.length){
var albumNames = newAlbumList.map(function(album){
return album.name;
});
if(albumNames.indexOf($scope.selectedAlbum)<0)
scope.selectedAlbum = newAlbumList[0].name;
}
});
side note:
you can rewrite your html with ng-options:
<select class="rounded bold" ng-options="album.albumName for album in albumsList"></select>
Simply u can make this with old JavaScript :
var elementid=document.getElementById("elementid");
var unknown_option=elementid.options[1].value;
elementid.value=unknown_option;
//options[1] selects the first option, if 2 then the 2nd.. etc
but of course if u want the last option u will have to make length function then loop or directly "inverted index" :)
I have some web pages which display a number of (up to several dozen) work items.
Each work item is a form consisting of several fields, two of which are large selects (one about 350 items and the other about 650 options) which are always identical other than the initially selected item.
The page can be pretty slow to load. Some of this may be due to the 24KB + 52KB of html for each copy of those selects, and I'm betting a fair amount of it is the time for the browser to build what is essentially the same huge chunk of (mostly of no interest) DOM over and over again.
What I'm thinking might be better is to just keep a master copy of the options for each in an array and just start each select out with only a single option (the initially selected value), For example:
<form ...>
<input ...>
<select class='dept_select' id='dept' name='dept' size='1'>
<option value='12345' selected>Department of Banking and Finance
</select>
<select class='approver_select' id='approver' name='approver' size='1'>
<option value='jpflat' selected>J. Pierpont Flathead
</select>
</form>
and then when the user clicks on the one selectbox they are interested in, build the rest of it from the array. Is this at all sensible, and if it might be, is there some clever and succinct way to do this in jQuery or am I going to have to invent it from whole cloth and raw JavaScript? FWIW, there's no real correlation between the selects (e.g., like selecting a state limits the valid choices for selecting a city).
I'm not going to post code so far. I recommend to re-build your concept a bit to get to a simpler structure:
A user can only edit one item at a time. There's no need to generate "a couple of dozen forms", as long as no edit action is taken.
render the items as a simple two-dimensional array with rows and fields, preferable in a JSON
built the table of items dynamically in the client by use of jQuery
if the user wants to edit an item, open a div layer, render a form into it by the use of the above array. Of course with just one single set of these dropdowns.
consider to load these dropdowns on request by AJAX or use some "combo box" features like in jQuery ui (below).
on "save" submit the form and close the div layer
There are certain containers and dialogs ready-to-use in jQuery ui to achieve this. The result will be
more generic code
less html overhead
better usability even
Well, turns out it wasn't as hard as I was imagining it...
<form ...>
<select id="ts" name="ts" size="1" class="tsc">
<option value="12345" selected>This is the initial value</option>
</select>
</form>
and:
var arr = [
{V:'alpha',T:'One'},
{V:'bravo',T:'Two'},
{V:'charlie',T:'Three'}
];
$(function() {
$( '.tsc' ).mousedown(function() {
var sel = $(this);
sel.unbind('mousedown');
$(arr).each(function() {
sel.append($('<option>')
.attr('value', this.V)
.text(this.T));
});
});
});
jQuery rocks.
I'm developing an Angular app and I have a form set up which I need to run validation on. One of the form elements is a <select>, like this:
<select name="noOfPeople" ng-model="noOfPeople">
<option>No of people*</option>
<option ng-repeat="amt in [] | range:12">{{ amt +1 }}</option>
</select>
Because the design doesn't allow for labels on form elements, the label is essentially the first option in the select element. I want this control to be invalid unless it matches the following pattern: /^[0-9]$/.
I have tried using ng-pattern on the <select> however that doesn't seem to have any effect, Angular always thinks the control is valid.
The only other way I can think of doing it is writing a function in my controller to check if this control is valid and block the form from submitting if it's not. But I don't want to introduce a random validation function into my nice clean controller.
What's the best way to deal with this?
You can use the ng-options attribute here, rather than ng-repeat, and attribute a blank value to any options you wish to ignore. For example:
<select name="noOfPeople" ng-model="noOfPeople" ng-options="value for value in [] | range:12">
<option value="">No of people*</option>
<option value="">This won't count either!</option>
</select>
<p>Selected Value: {{noOfPeople}}<p>
If you explicitly require the regex checking to occur, you could write a filter and add it to the ng-options.
I'm using AngularJS with AngularStrap (directive Select, based on Bootstrap-Select made by Silvio Moreto). I have the next problem:
I have an array of car brands. Using ng-options, I put them like options in a select.
By other way, when I select an option (car brand), I get the different models of this car brand, and show them like options in another select.
The problem is when I'm using the AngularStrap directive select, it doesn't work well. The first time i select a car brand, it works fine, but the next selected option (car brand), it shows the models of the car brand selected and the first model of the previous car brand selected.
When I don't use AngularStrap select it works well, therefore i think the problem is in AngularStrap select.
Thanks for your help.
My code is the next:
HTML:
<select ng-model="selectBrand" ng-options="carBrand.id as boatBrand.name for boatBrand in boatBrands" bs-select >
<optionvalue="">CarBrand</option>
</select>
<select ng-model="selectModel" ng-options="carModel.id as carModel.name for boatModel in carModels" bs-select>
<option value="">CarModel</option>
</select>
Controller (JS):
$scope.carBrands = carBrand.query();
$scope.$watch('selectBrand', function() {
$scope.carModels = carModel.query({type_id: $scope.selectBrand});
};
I realize this is old, but I had a similar problem with the Chosen Select plugin and a dynamic list of ng-options. I finally resolved the problem by wrapping my options query inside of a $timeout.
$timeout(function () {
$scope.carModels = carModel.query({type_id: $scope.selectBrand});
});
The only way I was able to use the AngularStrap select support with a select element was to use ng-options and have no option elements as children of the <select>.