Angular JS order select using key/value - javascript

I just asked about generating a select from key/value map instead of array: AngularJS select box generated from object
That is all working fine now: http://jsfiddle.net/UPWKe/1/
<select ng-model="current.addressCode" ng-options="value.code as value.name for (key, value) in student.address | orderBy: 'code'"</select>
... and js ...
$scope.student = {
address: {
select: {
code: "0",
name: "Select proof of address"
},
letter: {
code: "1",
name: "Letter"
},
photograph: {
code: "3",
name: "Photograph"
}
},
But the only thing missing, is how to order the select items.
How can I order select items in a select box generated from key/value map in angularjs?

Solution 1: You can use another array to store the order of the fields. For this you would need to use ng-repeat in place of ng-options:
$scope.studentAddressFields = [
"select",
"letter",
"photograph"
]
HTML:
<select ng-model="current.addressCode">
<option ng-repeat="field in studentAddressFields"
value="student.address[field]['code']">
{{student.address[field]['name']}}
</option>
</select>
Solution 2: Using a filter:
HTML:
<select ng-model="current.addressCode" ng-options="code as details.name
for (code, details) in student.address | getOrdered">
</select>
Filter:
myApp.filter('getOrdered', function() {
return function(input) {
var ordered = {};
for (var key in input){
ordered[input[key]["code"]] = input[key];
}
return ordered;
};
});

Related

How to set a value in a select from an object in angularjs

I'm new to Angular so please be gentle :)
I am recieving a "Brand" Object from the server and I want to set the select field with the good corresponding value.
Brands look like this :
Brands = [{name: "BRAND1", id=242},
{name: "BRAND2", id=562}]
And I got from the server:
brandFromTheServer = {name: "BRAND2", id=562};
This is my select :
<select id="brand" ng-model="product.brand" class="form-control" ng-options="brand as brand.name for brand in brands"></select>
And I want the select to be set with brandFromTheServer.
I tried in the controller:
$scope.product.brand = brandFromTheServer;
How can I set the value of the select with the brand that I'm recieving ?
Sorry, my English is terrible !
Please help :=)
I use something like this:
<select ng-options="option.name for option in advertiserList" ng-model="selectedOption.advertiserChoice" class="form-control"></select>
And in my controller I have:
$scope.advertiserList = response.advertisers;
var data = $scope.advertiserList.getIndexBy("id", $scope.currentAdvertiser.id)
$scope.selectedOption.advertiserChoice = $scope.advertiserList[data];
The method getIndexBy() is like this:
Array.prototype.getIndexBy = function (name, value) {
for (var i = 0; i < this.length; i++) {
if (this[i][name] === value) {
return i;
}
}
}
And my advertiserList json looks like this:
"advertisers": [
{
"id": 1,
"name": "Somebody Franck",
},
{
"id": 2,
"name": "Me Me me",
}
]
<select id="brand" ng-model="product.brand" class="form-control" ng- options="brand as brand.name for brand in brands">
<option value="o">Val 1</option>
<option value="1">Val 2</option>
<option value="2">Val 3</option>
</select>
$scope.product.brand = 0 or 1 or 2;
Your approach is correct when using ng-options, however the product.brand is not bound to the Brand object. Something like this works:
Controller:
$scope.brands = [
{
name: '1'
},
{
name: '2'
},{
name: '3'
}
];
$scope.product = {
brand: $scope.brands[1] // now it has a 'reference'
};

Angularjs Dropdown OnChange Selected Text and Value

I am new to AngularJS and trying to get Selected Text and Value from Dropdown. I followed a lot of tutorials with still unable to get there. SelectedValue and SelectedText are always undefined. Below is my code:
Html:
<div ng-app="SelectApp">
<div ng-controller="selectController">
<select name="category-group" id="categoryGroup" class="form-control" ng-model="itemSelected" ng-change="onCategoryChange(itemSelected)">
<option value="0">Select a category...</option>
<option ng-repeat="category in categories" value="{{category.id}}"
ng-disabled="category.disabled" ng-class="{'mainCategory' : category.disabled}">
{{category.name}}
</option>
</select>
</div>
Js:
'use strict';
var app = angular.module('SelectApp', [ ]);
app.controller('selectController', ['$scope', '$window', function ($scope, $window) {
$scope.categories = [
{ id: 1, name: "- Vehicles -", disabled: true },
{ id: 2, name: "Cars" },
{ id: 3, name: "Commercial vehicles", disabled: false },
{ id: 4, name: "Motorcycles", disabled: false },
{ id: 5, name: "Car & Motorcycle Equipment", disabled: false },
{ id: 6, name: "Boats", disabled: false },
{ id: 7, name: "Other Vehicles", disabled: false },
{ id: 8, name: "- House and Children -", disabled: true },
{ id: 9, name: "Appliances", disabled: false },
{ id: 10, name: "Inside", disabled: false },
{ id: 11, name: "Games and Clothing", disabled: false },
{ id: 12, name: "Garden", disabled: false }
];
$scope.onCategoryChange = function () {
$window.alert("Selected Value: " + $scope.itemSelected.id + "\nSelected Text: " + $scope.itemSelected.name);
};
}]);
And one more thing, I have defined my first item as Select a category... then Why first item in Dropdown is always empty.
Below is my fiddle sample.
http://jsfiddle.net/Qgmz7/136/
That's because, your model itemSelected captures the current value of your select drop down which is nothing but the value attribute of your option element. You have
<option ng-repeat="category in categories" value="{{category.id}}">
in your code, so in the rendered version, you'll get
<option ng-repeat="category in categories" value="0">
but you're expecting itemSelected to be your category object and any attempt to query id or other property will return undefined.
You can use ng-options with group by with little bit of change to your data or you can use normal ng-repeat, get the selectedIndex and lookup the category object from your categories list using that index. Showcasing the first approach here.
HTML
<select name="category-group" id="categoryGroup"
ng-model="itemSelected" ng-change="onCategoryChange(itemSelected)"
ng-options="category.name group by category.group for category in categories">
</select>
Updated Data
$scope.categories = [
{ id: 0, name: "Select a category..."},
{ id: 1, name: "Cars", group : "- Vehicles -" },
{ id: 2, name: "Commercial vehicles", group : "- Vehicles -" },
{ id: 3, name: "Motorcycles", group : "- Vehicles -" }
];
$scope.itemSelected = $scope.categories[0];
Instead of disabled property, you can add a group property which can be used in group by.
Here' an updated Fiddle to illustrate the idea.
You should use ng-options to set object to your ng-model value on change of you select options.
Markup
<select name="category-group" id="categoryGroup" class="form-control"
ng-model="itemSelected" ng-change="onCategoryChange(itemSelected)"
ng-options="category.name for category in categories">
<option value="0">Select a category...</option>
</select>
Fiddle Here
Update
For persisting style you have to use ng-repeat there, in that case you will only have id binded to your ng-model and while retrieving whole object you need to filter your data.
$scope.onCategoryChange = function () {
var currentSelected = $filter('filter')($scope.categories, {id: $scope.itemSelected})[0]
$window.alert("Selected Value: " + currentSelected.id + "\nSelected Text: " + currentSelected.name);
};
Updated Fiddle
<div ng-app="SelectApp">
<div ng-controller="selectController">
<select ng-change='onCategoryChange()' ng-model="itemSelected" ng-options="category.name for category in categories">
<option value="">-- category --</option>
</select>
</div>
//http://jsbin.com/zajipe/edit?html,js,output
A little change in your onCategoryChange() should work:
$scope.onCategoryChange = function () {
$window.alert("Selected Value: " + $scope.categories[$scope.itemSelected - 1].id + "\nSelected Text: " + $scope.categories[$scope.itemSelected -1].name);
};
JSFiddle: http://jsfiddle.net/Qgmz7/144/
ngChange only returns the value of your selected option and that's why you don't get the whole data.
Here's a working solution without changing your markup logic.
Markup:
<select
name="category-group"
id="categoryGroup"
class="form-control"
ng-model="id"
ng-change="onCategoryChange(id)">
ngChange handler:
$scope.onCategoryChange = function (id) {
//get selected item data from categories
var selectedIndex = $scope.categories.map(function(obj) { return obj.id; }).indexOf( parseInt(id) );
var itemSelected = $scope.categories[selectedIndex];
$window.alert("Selected Value: " + itemSelected.id + "\nSelected Text: " + itemSelected.name);
};
Another solution (little bit dirty) would be to change only the value of your options into something like this:
<option .... value="{{category.id}}|{{category.name}}">
...and inside your actual ngChange handler, just split the value to get all the values as an array:
$scope.onCategoryChange = function (itemSelected) {
$scope.itemSelected = itemSelected.split('|'); //string value to array
$window.alert("Selected Value: " + $scope.itemSelected[0] + "\nSelected Text: " + $scope.itemSelected[1]);
};
Here very Simple and easy code What I did
<div ng-app="myApp" ng-controller="myCtrl">
Select Person:
<select ng-model="selectedData">
<option ng-repeat="person in persons" value={{person.age}}>
{{person.name}}
</option>
</select>
<div ng-bind="selectedData">AGE:</DIV>
<br>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl',myCtrlFn);
function myCtrlFn($scope) {
$scope.persons =[
{'name': 'Prabu','age': 20},
{'name': 'Ram','age': 24},
{'name': 'S','age': 14},
{'name': 'P','age': 15}
];
}
</script>

How to convert id as order number in ng-options group by..?

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>

Angularjs: update select options

I have two select menus . One for country selection and other for state. I need to update states based country selected. I am able to log states but not able to list them in select menu.Please help.
Angular:
angular.module('demoApp', []).controller('DemoController', function($scope) {
$scope.countries = [
{ label: 'Please select', value: 0 },
{ label: 'India', value: 1 },
{ label: 'US', value: 2 }
];
$scope.data = [{'1':[{ label: 'Delhi', value: 0 },{ label: 'Mumbai', value: 1 },{ label: 'Chennai', value: 2 }]},
{'2':[{ label: 'Alabama', value: 3 },{ label: 'Alaska', value: 4 },{ label: 'Arizona', value: 5 }]}];
$scope.vm = {states: []};
$scope.updateStates = function(countryCode){
$scope.vm.states = $scope.data[countryCode-1];
console.log($scope.vm.states);
};
$scope.correctlySelected = $scope.countries[0];
});
HTML:
<body ng-app="demoApp">
<div ng-controller="DemoController">
<select ng-model="correctlySelected" ng-change="updateStates(correctlySelected.value)" ng-options="opt as opt.label for opt in countries">
</select>
<select ng-options="opt as opt.label for opt in vm.states">
</select>
</div>
</body>
JS Bin:
http://jsbin.com/pafosewedo/1/edit?html,js,console,output
You need to add ng-model to your states <select> - this is required when you are using ng-options
You also have an inconvenient model for the states data. Each element of the data array that corresponds to the country's states is an object with a changing key whose value is an array of states. You could make it work, but it's better to change it to something more reasonable:
$scope.data = {
1: [{ label: 'Delhi', value: 0 }, {...}, ],
2: [{...}, {...}, ] // same for US
}
Then it would work with how you specified your ng-options for states, and you wouldn't have to deal with indices:
$scope.updateStates = function(countryCode){
$scope.vm.states = $scope.data[countryCode]; // access by property
};
I think, that you should use some filter like that if you don't want to change your model:
.filter('stateFilter', function() {
return function(states, countryID) {
var filtered = [];
angular.forEach(states, function(state){
if(state.value === countryID)
filtered.push(state);
});
return filtered;
};
});
to filter out all values that have value equal to selected country.value in first select control.
To use that filter you need to modify your ng-repeat directive value in state select control:
ng-options="state as state.label for data | stateFilter:correctlySelected"
I came up with the following solution, view my JSBin
This solutions works by setting the countryCode in the scope when we are updatingStates.
$scope.updateStates = function(countryCode){
$scope.countryCode = countryCode;
$scope.vm.states = $scope.data[countryCode-1];
console.log($scope.vm.states[countryCode]);
};
This change is then reflected in the view.
<select>
<option ng-repeat='i in vm.states[countryCode]'> {{i.label}}
</option>
</select>

ngOptions two level object display

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.

Categories

Resources