I'm facing a problem with setting a value in a drop-down list. The following is the code for my drop-down:
<select class="price-dropdown" ng-model="createCampaign.currency" ng-options="obj.id as obj.symbol for obj in config.currencies"></select>
Here is the object:
[Object, Object]
0: Object
id: "GBP"
name: "GBP"
symbol: "GBP"
__proto__: Object
1: Object
id: "dollar"
name: "Dollar"
symbol: "$"
__proto__: Object
length: 2
__proto__: Array[0]
It's setting 0, 1, 2 as the value instead of id.
I've looked at other questions but haven't been able to make any of the solutions work.
What am I doing wrong?
Its setting the object Ordinal it seems. can you debug and edit in {obj.id} inside ng-options="obj.id as obj.symbol for obj in config.currencies"> to get it right.
I have created a Fiddle for your problem. Over here it is having id as value.
Code Snippet:
<div ng-app="myapp">
<fieldset ng-controller="FirstCtrl">
<select
ng-options="p.name as p.name for p in symbol"
ng-model="selectedPerson"></select>
{{ selectedPerson }}
</fieldset>
</div>
I Think a dropdown list must have a unique identifier among the list.. to identify the correct selection..look in this sample fiddle link it may help you..
<select class="span2" name="SelectedState" ng-model="selectedState" ng-options="state.id as state.name for state in states">
</select>
Controller code:
$scope.states = [{
id: 1, name: 'France'
}, {
id: 2, name: 'UK'
}, {
id: 3, name: 'Germany'
}];
$scope.selectedState = $scope.states[2];
This code will help to solve your problem please check it once
$scope.colors = [
{name:'black', shade:'dark'},
{name:'white', shade:'light'},
{name:'red', shade:'dark'},
{name:'blue', shade:'dark'},
{name:'yellow', shade:'light'}
];
<select name="value">
<option ng-repeat="color in colors" value="{{color.name}}">
{{color.name}}
</option>
</select>
It's not bug, it's a feature. angularjs handles ngOptions and ngModel internally, this way it allows you to use any type of object as value in option rather than only strings. This link should help you :) Watch this tutorial this is shortcut for your problem.
Related
I have this following html code for select tags.
<option ng-repeat="option in AllData" value="{{item.Id}}" ng-selected="data.Symbol==item.Id">{{item.Symbol}}</option>
I want to convert this to ng-options. can someone please shed some light on this.
the value of AllData is as follows. It is an array of objects.
0:Object
Id: 1
Symbol: "GR"
1:Object
Id: 2
Symbol: "DR"
I tried something like this but was not successful.
ng-options="item as item .Symbol for item in AllData track by item.Id">
Try this
<select ng-options="option as option.Symbol for option in AllData">
</select>
when using ngOptions, you have to also bind ng-model with the initial value of select.
mention that since you used track by item.Id, the default value should at least contains property Id and meets the one of the items Id property.
refer the below sample:
angular.module("app", [])
.controller("myCtrl", function($scope) {
$scope.AllData = [{
0: Object,
Id: 1,
Symbol: "GR"
}, {
1: Object,
Id: 2,
Symbol: "DR"
}];
//$scope.data = $scope.AllData[0];
$scope.data = {
0: Object,
Id: 1,
Symbol: "GR"
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<div ng-app="app" ng-controller="myCtrl">
<select ng-model="data" ng-options="item as item.Symbol for item in AllData track by item.Id"></select> {{selectedItem}}
</div>
I just recently figured out that there is an alternative for value property on OPTION part of the SELECT, namely ngValue. The docs really lack documentation about this (all I could find: https://angular.io/docs/ts/latest/api/forms/index/NgSelectOption-directive.html). Anyway, the idea is that when you use an object for the ngModel, you can use ngValue and it works well. Otherwise, only e.g. ID is updated. If we're having just an array of strings, value is sufficient. Here are the examples:
{{myModel | json}}
<select [(ngModel)]="myModel">
<option *ngFor="let i of items" [ngValue]="i">{{i.value}}</option>
</select>
<br /><br />
{{mySimpleModel}}
<select [(ngModel)]="mySimpleModel">
<option *ngFor="let i of simpleItems" [value]="i">{{i}}</option>
</select>
While this works as expected, there's a distinctive differences between the two: if using ngValue, the predefined value is not selected in the drop down, whereas for the primitive types, the value is selected on loading. E.g.:
items: any[] = [{id: 1, value: 'item1'}, {id: 2, value: 'item2'}, {id: 3, value: 'item3'}];
myModel: any = {id: this.items[1].id , value: this.items[1].value};
simpleItems: string[] = ['item1', 'item2', 'item3'];
mySimpleModel: string = this.simpleItems[1];
See example here: https://plnkr.co/edit/JBrtmx7QkPZztBjaqYkS?p=preview
So, why does Angular set the default value for strings, but not for objects? And what is the most elegant workaround?
You don't need a "workaround" for that. When you do this
myModel = {id: this.items[1].id , value: this.items[1].value};
you are creating a new object which has the same values as this.items[1] but it is not the same object, it's a new one.
const items = [{id: 1, value: 'item1'}, {id: 2, value: 'item2'}, {id: 3, value: 'item3'}]
const myModel = {id: 2, value: 'item2'};
console.log(items[1] === myModel);
that is the reason why your select can't find that value in the <option> list.
In order to fix that, you have to use a proper reference
items = [
{id: 1, value: 'item1'},
{id: 2, value: 'item2'},
{id: 3, value: 'item3'}
];
myModel = this.items[1]
plunkr
In order to obtain default selected option using [ngValue] you can use [compareWith].
Just change in the method compareObj the correct atribute for the Object your comparing.
<select [compareWith]="compareObj" [(ngModel)]="selectedObject">
<option *ngFor="let object of objects" [ngValue]="object">
{{object.name}}
</option>
</select>
compareObj(o1: Object, o2: Object) {
return o1.id === o2.id;
}
I have a multidimensional array that holds the product names and versions.
I want to create an interface that lets the user select the product from a select box, and then the version number in the second select box. The second select box should only show the versions numbers of the product that the user selected in the first select box.
This is my mutidimensional array:
[Object]0:
name: "Product 1"
versions: [Array]0:
number: "1.0"
number: "1.5.2"
1:
name: "Product 2"
versions: [Array]0:
number: "0.0"
number: "0.5"
The user has the option to choose multiple products, so I created an array to hold the users selection.
my controller is setup like this:
app.controller('mainController', function ($scope) {
$scope.products = [{id: 1, name: '', versions: []}];
$scope.packages = [];
$scope.packages[0] = { id: 1, name: 'Product 1', versions: [{number: 1.0}, {number: 1.5}, {number: 2.0}]};
$scope.packages[1] = { id: 2, name: 'Product 2', versions: [{number: 0.1}, {number: 0.2}, {number: 0.3}]};
$scope.addProduct = function(){
var id = $scope.products.length + 1;
$scope.products.push({id: id, name: "", version: []});
};
});
And the select boxes are setup like this with angularjs:
<div ng-repeat="product in products">
<label>Product</label>
<select ng-model="product.product" ng-options="package.name for package in packages" class="form-control"></select>
<label>Version</label>
<select ng-model="product.versions" ng-options="version.number for version in product.versions" class="form-control"></select>
</div>
<button ng-click="addProduct()">Add Product</button>
What I tried to do was setup the ng-options to select the versions object of the current product. But this doesn't work.
I created a jsFiddle of what I currently have:
http://jsfiddle.net/rkyu4rjq/
I would really appreciate any suggestions on how to link the version select box with the product selected.
TIA
Eventhough I'm not really keeping track of which version chosen for each product I fixed your relative select options.
You can find a solution here. This should get you on your way!
I missed something very simple.
In the version select box binding I should of used version.number for version in product.product.versions instead of version.number for version in product.versions
Here is a working jsFiddle: http://jsfiddle.net/rkyu4rjq/2/
This is my code
Fiddle Link
HTML
<div ng-app ng-controller="MyCtrl">
<input type="text" ng-model = "data.name" ><br>
<input type="text" ng-model = "data.value" ><br>
<input type="text" ng-model = "data.id" ><br>
<input type="button" value="ADD" ng-click = "addIntoArr(data.name,
data.value, data.id)" ng-disabled= !data.name>
<select ng-model="selectItem" ng-options="currOption as 'order' +
(data.indexOf(currOption)+1) group by currOption.name for currOption
in data"></select>
Data : {{selectItem.name}}
</div>
Here is my Js code
function MyCtrl($scope) {
$scope.data = [{
name: "AM",
value: "11",
id: "2"
}, {
name: "PM",
value: "12",
id: "3"
}, {
name: "PM",
value: "12",
id: "23"
}, {
name: "PM",
value: "12",
id: "33"
}, {
name: "AMT",
value: "13",
id: "33"
}, {
name: "WAT",
value: "14",
id: "21"
}];
$scope.addIntoArr = function (name, value, id) {
$scope.data.push({
name: name,
value: value,
id: id
});
}
$scope.selectItem = $scope.data[0];
}
Here is my array I was using label AM, PM, AWT, WAT. and each has a order (Please check fiddle link). I want each label order show with number like order1 in AM, order1, order2, order3 in PM and so on. and if I add new entry in array then recently added entry should be shown in drop down with order number and Related label shown in Data.
You cannot use $index inside ng-options. However you can get the current index by using indexOf on the data item passing the current option.
<select
ng-model="selectItem"
ng-options="currOption as 'order' + (data.indexOf(currOption)+1) group by currOption.name for currOption in data"></select>
Demo http://jsfiddle.net/6cf3h54x/3/
I'd suggest you include some external library like lodash and format your data into more convenient structure. Then, instead of banging your head against the wall with ng-options, you could use ng-repeat.
Consider the following:
// group existing data by object's name using lodash _.groupBy
$scope.groupedData = _.groupBy($scope.data, 'name');
This gives your following data structure for groupedData, so there's key and value where key is e.g. AM and value is array of objects all having same name.
Then you could have following template for your select.
<select ng-model="selectItem">
<optgroup ng-repeat="(key, items) in groupedData" label="{{ key }}">
<option ng-repeat="item in items"
value="{{ item }}"
ng-bind="'order' + (items.indexOf(item) + 1)"></option>
</optgroup>
</select>
Which gives you what you are after, no?
You can't use $index with ng-options. Make use of indexOf instead. You can do something like this:
<select ng-model="selectItem" ng-options="currOption.id as 'order'+data.indexOf(currOption) group by currOption.name for currOption in data"></select>
I have this structure:
model = [
{
name: 'name1',
items: [
{
name: 'subobj1'
},
{
name: 'subobj2'
}]
},
{
name: 'name2',
items: [
{
name: 'subobj1'
},
{
name: 'subobj2'
}]
},
....
]
Question is: How do I write ngOptions attrbiute to output this object like this?:
<select>
<optgroup label="name1">
<label>subobj1</label>
<label>subobj2></label>
</optgroup>
....
</group>
Also - ngRepeat is not an option. I have to do this ngOptions alone for plugin being used to work.
ngOptions doesn't support multi-dimensional arrays. You must flatten your array first.
Read more in this answer.
I used a filter:
app.filter('flatten' , function(){
return function(array){
return array.reduce(function(flatten, group){
group.items.forEach(function(item){
flatten.push({ group: group.name , name: item.name})
})
return flatten;
},[]);
}
})
And the markup:
<select ng-model="select"
ng-options="item.name
group by item.group
for item in model | flatten"></select>
<select>
<option ng-repeat-start="m in model" ng-bind="m.name"></option>
<option ng-repeat-end ng-repeat="item in m.items" ng-bind="item.name"></option>
</select>
You might add something like style="font-weight: bold;" on the first option (which is the group label, by the way) and something like style="padding-left: 15px;" on the second option line, which is another repeat for all the first option line.
So basically by doing this you just add 2 levels (without optgroup tag, mind you) to your select.