Angular ng-options in select2 - settings value property - angularjs

I have an array of countries:
var countriesList: [
{name: "Israel", code: "IL"},
{name: "India", code: "IN"},
{name: "Andorra", code: "AD"}
]
and an array of selected countries:
selectedCountries: [
{
country:"IL"
}
]
I'm using select2 for selecting countries.
I started with ng-repeat for generating the <options/> tag:
<select
id="countriesList"
ui-select2
multiple
ng-model='data.selectedCountries'
data-placeholder='Choose or Search for Countries'
name='locations'
ng-change='geoTargetingChanged()'>
<option ng-repeat="country in data.countriesList" value="{{country.code}}">{{country.name}}</option>
</select>
this method worked well, but it caused the form to be $dirty right at start.
so I started using the `ng-options- mechanism (after reading this answer):
<select
id="countriesList"
ui-select2
multiple
ng-model='data.selectedCountries'
data-placeholder='Choose or Search for Countries'
name='locations'
ng-change='geoTargetingChanged()'
ng-options="country.code as country.name for country in data.campaignSettings.countriesList">
<option></option>
</select>
Now the problem is that the value of the items is not the country code, it is their index in the array.
Am i missing something?

Here is a plunker.
I don't see any issue, although I did change the format of selectedCountries to be an array of country codes (["IL", ...]) instead of the data structure you provided ([{country:"IL", ...}]).
Angular does generate the options using the index as the value, but the ngModel will contain the propper value. If you are doing form submission with the select, you should be using the data out of the ngModel instead of the data from the select in the HTML. If you need to put the data from the select on the page in a form, you could put the values of the select's ngModel into hidden form elements.

If you're ok with having the chosen items being a mirror of what is in your countriesList like so:
$scope.data.selectedCountries = [$scope.data.countriesList[0]];
ng-options="country as country.name for country in data.countriesList">
Then here's an updated plunkr of how to accomplish what you need: http://plnkr.co/edit/qE3SJm?p=preview
If instead, you do just want the country code, when you're assigning it into the selectedCountries, you have to reference the actual location it is within the country array:
$scope.data.selectedCountries = [$scope.data.countriesList[0].code];
ng-options="country.code as country.name for country in data.countriesList">
Other plunkr: http://plnkr.co/edit/ysAatS?p=preview

try this:
<select style="width: 100%" ui-select2="{multiple: true}" ng-model="countriesList" class="form-control select2" multiple style="width:300px">
<option></option>
<option ng-repeat="country in countriesList" value="{{country}}">{{country}}</option>
</select>
assuming the structure is like #rtcherry mentioned.

Related

Map ng-model array values with the object of ng-options for selected options

I have following values:
campaign_sms_templates = [11,22];
and
templateSMSList = [
{"id":11, "name":"test"},
{"id":12, "name":"test 12"},
{"id":22, "name":"test 22"}
];
And angular code is like:
<select multiple="multiple"
ng-model="campaign_sms_templates"
ng-options="value as value.name for value in templateSMSList track by value.id">
</select>
But values are not selected on rendering. When I change campaign_sms_templates parameter values with:
campaign_sms_templates = [ {"id":11}, {"id":22} ];
It works as objects matches and on rendering it displays selected values.
Can anyone help, how I can render selected options by using these values:
campaign_sms_templates = [11,22];
Please do let me know if is there anything need more clarifications.
After spending lots of time in this, now finally I have resolved this
<select multiple="multiple" ng-change="save(campaign_sms_templates)" ng-model="campaign_sms_templates">
<option value=[[field.id]] ng-repeat="field in templateSMSList" ng-selected="campaign_sms_templates.indexOf(field.id)!==-1">[[field.name]]</option>
</select>
It seems not a good practice but as I only want to save ids in my database documents so I did this.
Any feedback are welcome.
Use value.id as value.name for value:
<select multiple="multiple"
ng-model="campaign_sms_templates"
ng-options="value.id as value.name for value in templateSMSList">
</select>
Also leave out the track by expression as it is not needed and will break the directive.
For more information, see
AngularJS ng-options Directive API Reference - select as and track by.

How to apply filter on ng-options in case of nested json object

I have two json arrays for country and for state. Now I have to filter the state drop down based on country selection.
The two JSON arrays are like this.
$scope.countries = [{id:1,json:{'key':'1',value:'INDIA'}},{id:2,json:{'key':'2',value:'USA'}}];
$scope.states = [{id:1,json{'key':'1',value:'MAHARASTRA',prntkey:'1'}},{id:2,json{'key':'2',value:'TELANGANA',prntkey:'1'}},{id:3,json{'key':'3',value:'NEW YORK',prntkey:'2'}},{id:4,json{'key':'4',value:'TEXAS',prntkey:'2'}}].
I am binding these json arrays to select tags of country and state using ng-options.
<select ng-model="country" ng-options="option as option.json.value for option in countries track by option.json.key">
<option value="">- Select -</option>
</select>
<select ng-model="state" ng-options="option as option.json.value for option in states | filter:{prntkey:country.json.key} track by option.json.key">
<option value="">- Select -</option>
</select>
Now if I select the country as INDIA the corresponding states (MAHARASTRA, TELANGANA) should be populated in state drop down. The above code is not working. Can any one please rectify the mistake if any in the above code. Thanks in advance.
In second dropdown you are filtering with deep property 'prntkey'. To filter with deep/nested property, you need to provide complete path of property.
Use
filter:{json: {prntkey:country.json.key}}
instead of
filter:{prntkey:country.json.key}
Update:
For keeping state dropdown empty if country is not selected, you can use custom filter function.
Add following function in your controller
$scope.filterState = function(input){
return $scope.country && $scope.country.json.key === input.json.prntkey;
};
And replace state filter filter:{prntkey:country.json.key} with filter: filterState

angular ng-model has not work in select tags

I am using ng-model on select tags, but those are a part of works. The code is
<select ng-model="uptpm.point" ng-if="uptpm.leval.length>0" class="form-control text-center nopaddingleft nopaddingright" ng-change="setPoint(uptpm)">
<option value="{{uptpml.value}}" ng-repeat="uptpml in uptpm.leval">{{uptpml.value}}</option>
</select>`
the view is
the datas struct.
Display effect
It's not recommended to use ngRepeat within select/option elements.
Take a look at https://docs.angularjs.org/api/ng/directive/ngOptions
Taken from angularjs docs:
The ngOptions attribute can be used to dynamically generate a list of elements for the element using the array or object obtained by evaluating the ngOptions comprehension expression.
I have wrote an example below:
Angular:
$scope.uptpm = [
{value: '0'},
{value: '4'}
];
$scope.point = 2;
HTML:
<select ng-model="point" ng-options="i.value as (i.value) for i in uptpm">
<option value="" selected>Please Select</option>
</select>
See this plunker for a working example:
http://plnkr.co/edit/Yl2ZynulIuk3ApG9jmTl

Angular JS select tag ng model gives one empty option Issue

Using ng-model and ng-options properties I bind select html tag.
It properly bind all the data in options BUT one empty option is bind at first with " ".
I want to remove this empty option using angular
<select class="ng-pristine UserGroups selectGroupClass" ng-model='groupList' required ng-options='item.name for item in groupOptions track by item.name'></select>
$scope.groupOptions = [{
name: "What's Hot",
value: 'latest'
}, {
name: 'Trending',
value: 'popular'
}];
The empty option is generated when a value referenced by ng-model doesn't exist in a set of options passed to ng-options.
If you want to remove this empty option using angular select an initial value in your controller,
$scope.groupList = $scope.groupOptions[0];
Please check working example : Here
OR
You can add
<option style="display:none" value="">select a type</option>
In HTML
<select class="ng-pristine UserGroups selectGroupClass" ng-model='groupList' required ng-options='item.name for item in groupOptions track by item.name'>
<option ng-hide="true" value="">Select a Type</option>
</select>
Please check working example here : Demo for 2nd option
track by just helps Angular internally with array sorting and prevent duplicated items in array. The value of the options is defined by the first argument (in your case item). If you want it to be by id then you should use item as item.name for item in groupOptions
one of the items has a blank name is what I can think of! Just verify that if possible.. Use item.someOtherproperty for item if possible to debug that :)
Try this solution
<select ng-model="selected" ng-options="item as item.name for item in groupOptions">
<option value="">Choose</option>}
</select>
<div data-ng-bind="selected.name"></div>

How to set the value attribute for select options?

Source JSON data is:
[
{"name":"Alabama","code":"AL"},
{"name":"Alaska","code":"AK"},
{"name":"American Samoa","code":"AS"},
...
]
I try
ng-options="i.code as i.name for i in regions"
but am getting:
<option value="?" selected="selected"></option>
<option value="0">Alabama</option>
<option value="1">Alaska</option>
<option value="2">American Samoa</option>
while I am expecting to get:
<option value="AL">Alabama</option>
<option value="AK">Alaska</option>
<option value="AS">American Samoa</option>
So, how to get value attributes and get rid of "?" item?
By the way, if I set the $scope.regions to a static JSON instead of AJAX request's result, the empty item disappears.
What you first tried should work, but the HTML is not what we would expect. I added an option to handle the initial "no item selected" case:
<select ng-options="region.code as region.name for region in regions" ng-model="region">
<option style="display:none" value="">select a region</option>
</select>
<br>selected: {{region}}
The above generates this HTML:
<select ng-options="..." ng-model="region" class="...">
<option style="display:none" value class>select a region</option>
<option value="0">Alabama</option>
<option value="1">Alaska</option>
<option value="2">American Samoa</option>
</select>
Fiddle
Even though Angular uses numeric integers for the value, the model (i.e., $scope.region) will be set to AL, AK, or AS, as desired. (The numeric value is used by Angular to lookup the correct array entry when an option is selected from the list.)
This may be confusing when first learning how Angular implements its "select" directive.
You can't really do this unless you build them yourself in an ng-repeat.
<select ng-model="foo">
<option ng-repeat="item in items" value="{{item.code}}">{{item.name}}</option>
</select>
BUT... it's probably not worth it. It's better to leave it function as designed and let Angular handle the inner workings. Angular uses the index this way so you can actually use an entire object as a value. So you can use a drop down binding to select a whole value rather than just a string, which is pretty awesome:
<select ng-model="foo" ng-options="item as item.name for item in items"></select>
{{foo | json}}
If you use the track by option, the value attribute is correctly written, e.g.:
<div ng-init="a = [{label: 'one', value: 15}, {label: 'two', value: 20}]">
<select ng-model="foo" ng-options="x for x in a track by x.value"/>
</div>
produces:
<select>
<option value="" selected="selected"></option>
<option value="15">one</option>
<option value="20">two</option>
</select>
If the model specified for the drop down does not exist then angular will generate an empty options element. So you will have to explicitly specify the model on the select like this:
<select ng-model="regions[index]" ng-options="....">
Refer to the following as it has been answered before:
Why does AngularJS include an empty option in select? and this fiddle
Update: Try this instead:
<select ng-model="regions[index].code" ng-options="i.code as i.name for i in regions">
</select>
or
<select ng-model="regions[2]" ng-options="r.name for r in regions">
</select>
Note that there is no empty options element in the select.
You could modify you model to look like this:
$scope.options = {
"AL" : "Alabama",
"AK" : "Alaska",
"AS" : "American Samoa"
};
Then use
<select ng-options="k as v for (k,v) in options"></select>
It appears it's not possible to actually use the "value" of a select in any meaningful way as a normal HTML form element and also hook it up to Angular in the approved way with ng-options. As a compromise, I ended up having to put a hidden input alongside my select and have it track the same model as my select, like this (all very much simplified from real production code for brevity):
HTML:
<select ng-model="profile" ng-options="o.id as o.name for o in profiles" name="something_i_dont_care_about">
</select>
<input name="profile_id" type="text" style="margin-left:-10000px;" ng-model="profile"/>
Javascript:
App.controller('ConnectCtrl',function ConnectCtrl($scope) {
$scope.profiles = [{id:'xyz', name:'a profile'},{id:'abc', name:'another profile'}];
$scope.profile = -1;
}
Then, in my server-side code I just looked for params[:profile_id] (this happened to be a Rails app, but the same principle applies anywhere). Because the hidden input tracks the same model as the select, they stay in sync automagically (no additional javascript necessary). This is the cool part of Angular. It almost makes up for what it does to the value attribute as a side effect.
Interestingly, I found this technique only worked with input tags that were not hidden (which is why I had to use the margin-left:-10000px; trick to move the input off the page). These two variations did not work:
<input name="profile_id" type="text" style="display:none;" ng-model="profile"/>
and
<input name="profile_id" type="hidden" ng-model="profile"/>
I feel like that must mean I'm missing something. It seems too weird for it to be a problem with Angular.
you can use
state.name for state in states track by state.code
Where states in the JSON array, state is the variable name for each object in the array.
Hope this helps
Try it as below:
var scope = $(this).scope();
alert(JSON.stringify(scope.model.options[$('#selOptions').val()].value));

Resources