ngOptions ordering and selecting objects in array - arrays

I have a set of options in my controller that looks like this:
$scope.options = [
{one: 'ONE'},
{two: 'TWO'},
{three: 'THREE'}
];
My view looks like the following currently looks like this:
<div ng-repeat="goal in objectives">
...
<select ng-model="goal.choices" ng-options="value for (key, value) in options"> </select>
...
</div>
PROBLEM: the resulting dropdown is not sorted by obj occurence in array rather by alpha of each objects key AND there is no default option selected, i want the dropdown to default to 'one' not ''
What is the ng-options expression need to make this work?????
Thanks

Your $scope.options array isn't usable in ngOptions because you have an array of three entirely different objects (one has a one property, another a two property, and the last a three property). If you want the select to default to $scope.choices[0], then goal.choices needs to be set to $scope.options[0].
I had to make some guesses here, because you didn't include what $scope.objectives was, but I can imagine you were going for something like this:
http://jsfiddle.net/A5KkM/
HTML
<div ng-app ng-controller="x">
<div ng-repeat="goal in objectives">{{goal.choice}}
<select ng-model="goal.choice" ng-options="o.name for o in options"></select>
</div>
</div>
JavaScript
function x($scope) {
$scope.options = [{
name: 'ONE'
}, {
name: 'TWO'
}, {
name: 'THREE'
}];
$scope.objectives = [{ choice: $scope.options[0] }, { choice: $scope.options[1] }];
}

Related

AngularJS option length IE

I have option list of some types like car, bus in format like this: <option value="BUS" label="Bus">Bus</option> and when I want to count the length of the list I use angular.element(element[0].options).length in Chrome it returns the correct length, but on Internet Explorer it returns 1
Use element[0].options.length directly, instead of wrapping it in angular.element(). If your list is data driven (which I recommend) then you can also just check the length of your array that contains the data.
var list = document.getElementById('list');
console.log('list.options.length = ' + list.options.length);
<select id="list">
<option>A</option>
<option>B</option>
<option>C</option>
</select>
Regarding the data driven list, ideally you should have an array of vehicles/transports/anything (might be complex objects with properties or just unique strings). Once you expose that array to the view (via scope or this from controllerAs syntax) then you can generate the list of options using ngOptions. For example:
Controller JS:
$scope.items = [{
id: 1,
label: 'aLabel',
subItem: { name: 'aSubItem' }
}, {
id: 2,
label: 'bLabel',
subItem: { name: 'bSubItem' }
}];
Template HTML:
<select ng-options="item as item.label for item in items track by item.id" ng-model="selected"></select>

How to run multiple successive select buttons in AngularJS

I facing an issue with having multiple selects in angularJS where each one of them is linked to the previous one and the value depended on the previous item selected which looks like could be done easily by angular but I am having a hard time figuring out how do I make the index of one select be passed to another select and at the same time making it unresponsive until some value is selected.
I also created a fiddle for the same for people to fiddle around with it.
Here is the concerned HTML
<div ng-app="myApp">
<div ng-controller="testController">
<select ng-model="carBrand" name="carBrand" required ng-options=" brand for brand in brands"></select>
<select ng-model="carModel" name="carModel" required ng-options="model.name for model in cars[0]"></select>
<!--I want the car brand(cars[0]) to be dynamic here. It should be prefreberably blacked out or uneditable until a Car brand is selected and once that particular brand is selected all the models pertaining to that brand only should be displayed in the ajoining select button-->
</div>
</div>
and an example app.js. Find the complete one at the fiddle
var app = angular.module('myApp', []);
app.controller("testController", function($scope) {
$scope.brands = ['Ford', 'Honda', 'Hyundai', 'Mahindra',
'Maruti Suzuki', 'Nissan', 'Renault', 'Skoda', 'Tata', 'Toyota', 'Volksvagen'
];
$scope.carBrand = $scope.brands[0];
$scope.cars = [];
/*These cars[0] and cars[1] are static declared but could well be called from a REST API endpoint in angular. For simplicity lets say they are already present. */
$scope.cars[0] = $scope.cars[0] = [{
name: "Figo",
capacity: 45
}, {
name: "Ecosport",
capacity: 52
}, {
name: "Fiesta",
capacity: 45
}, {
name: "Endeavour",
capacity: 71
}];
});
How do I solve the issue of getting an index from one select and passing it to the other to make this work and probably an additional perk would be to make it unresponsive in case no brand is selected.
Try ng-change:
<select ng-model="carBrand" name="carBrand" required ng-options=" brand for brand in brands"
ng-change="selectedCar(carBrand)"></select>
This returns the index of the selected brand:
$scope.selectedCar = function(brand) {
$scope.carIndex = $scope.brands.indexOf(brand);
};
Use it with the other dropdown as:
<select ng-model="carModel" name="carModel" required
ng-options="model.name for model in cars[carIndex]"></select>
Working Fiddle
When you select something from the first select, carBrand goes from undefined to the selected brand. You thus want the second select to be disabled if the carBrand is undefined (falsy):
<select ng-disabled="!carBrand" ...>
Then, you need to second select to contain the models associated to the selected brand (which is carBrand). So you need something like
<select ng-options="model.name for model in getModelsOfBrand(carBrand)" ...>
Now just implement this getModelsOfBrand(carBrand) function in the scope. It would be much easier if you had a better object model, like for example:
$scope.brands = [
{
name: 'Ford',
models: [
{
name: 'Figo',
capacity: 45
},
...
]
},
...
];
Then it would be as easy as
<select ng-options="model.name for model in carBrand.models" ...>

how do i filter items by property in ng-options?

I have some data and a select control as you can see from my code sample below. It works for me but I want to be able to filter the data by type. In my code sample, I show one way I have tried to filter the data based on the type being a value of one. I am not sure if the way I am creating the select is causing this simple inline filter to not work or if I am doing something wrong?
$scope.data = [{
name : "5 play",
type : 1
}, {
name : "one on one",
type : 2}, {
name : "two on one",
type : 2}];
<select class="form-control" ng-model="selectedRule"
ng-options="item as (item.Name) for item in data track by item.Name | filter:{type:1}"></select>
As stated in angular docs, track by must always be the last expression:
Note: track by must always be the last expression
My guess is that all that follows is not considered, so that´s why your filter wasn´t applying. Moving the track by to the right place should fix it
Yes, as mentioned. Move the track by at the end and make the letter N lowercase like in the following demo or in this fiddle.
angular.module('demoApp', [])
.controller('mainController', MainController);
function MainController($scope) {
$scope.data = [{
name: "5 play",
type: 1
}, {
name: "one on one",
type: 2
}, {
name: "two on one",
type: 2
}];
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demoApp" ng-controller="mainController">
<select class="form-control" ng-model="selectedRule" ng-options="item as item.name for item in data | filter:{type:1} track by item.name"></select>
</div>

Ng-repeat inside ng-repeat

<ul ng-repeat="cate in restaurant.categories"><li>{{cate}}</li>
<li ng-repeat="menuItem in restaurant.menuItems" ng-show="menuItem.category == cate">{{menuItem.name}}</li></ul>
I want one ng-repeat loop inside another and to show the menu only if the menuItem is in the category. I only have items in the first category loop, and empty for all the other categories.
Categories and menuItem are 2 different arrays. If the menuItem's category is under the current category it should be added to the page.
menuItems = {{name: dish1, category:soup},
{name: dish2, category:beef}}
categories = {beef, soup}
#show-me-the-code : Bill Bi has two different array. So the best option to achieve this is by filter in inside loop as stated in my comment.
Here is the final code with filter for inside loop. I am including fiddler for quick reference.
<div ng-app ng-controller="testCtrl">
<ul ng-repeat="cate in categories">
<li>{{cate}}</li>
<li ng-repeat="menuItem in menuItems | filter:{category: cate}">{{menuItem.name}}</li>
</ul>
</div>
function testCtrl($scope) {
$scope.menuItems = [{name: 'dish1', category:'soup'},
{name: 'dish2', category:'beef'}];
$scope.categories = ['beef', 'soup']
}
Fiddle : JSFiddle
I would change my data representation to match what you are actually trying to display like so:
$scope.restaurant = {
categories: [{
name: "beef",
menuItems: [{
name: "dish1",
"price": "$10"
}, {
name: "dish2",
"price": "$15"
}]
}, {
name: "soup",
menuItems: [{
name: "dish1",
"price": "$20"
}, {
name: "dish2",
"price": "$25"
}]
}]
};
This way you could easily match your two nested loops like this:
<div ng-app ng-controller="testCtrl">
<ul ng-repeat="cate in restaurant.categories">
<li>{{cate.name}}</li>
<li ng-repeat="menuItem in cate.menuItems">{{menuItem.name}} - {{menuItem.price}}</li>
</ul>
</div>
Check out this fiddle if you would like to see it in action.
If you need to stick to your JSON data, you will have to do filtering to pull the contents you want to display.

Setting default value in select drop-down using Angularjs

I have an object as below. I have to display this as a drop-down:
var list = [{id:4,name:"abc"},{id:600,name:"def"},{id:200,name:"xyz"}]
In my controller I have a variable that carries a value. This value decided which of the above three items in the array will be selected by default in the drop-down:
$scope.object.setDefault = 600;
When I create a drop-down form item as below:
<select ng-model="object.setDefault" ng-options="r.name for r in list">
I face two problems:
the list is generated as
<option value="0">abc</option>
<option value="1">def</option>
<option value="2">xyz</option>
instead of
<option value="4">abc</option>
<option value="600">def</option>
<option value="200">xyz</option>
No option gets selected by default even though i have ng-model="object.setDefault"
Problem 1:
The generated HTML you're getting is normal. Apparently it's a feature of Angular to be able to use any kind of object as value for a select. Angular does the mapping between the HTML option-value and the value in the ng-model.
Also see Umur's comment in this question: How do I set the value property in AngularJS' ng-options?
Problem 2:
Make sure you're using the following ng-options:
<select ng-model="object.item" ng-options="item.id as item.name for item in list" />
And put this in your controller to select a default value:
object.item = 4
When you use ng-options to populate a select list, it uses the entire object as the selected value, not just the single value you see in the select list. So in your case, you'd need to set
$scope.object.setDefault = {
id:600,
name:"def"
};
or
$scope.object.setDefault = $scope.selectItems[1];
I also recommend just outputting the value of $scope.object.setDefault in your template to see what I'm talking about getting selected.
<pre>{{object.setDefault}}</pre>
In View
<select ng-model="boxmodel"><option ng-repeat="lst in list" value="{{lst.id}}">{{lst.name}}</option></select>
JS:
In side controller
$scope.boxModel = 600;
You can do it with following code(track by),
<select ng-model="modelName" ng-options="data.name for data in list track by data.id" ></select>
This is an old question and you might have got the answer already.
My plnkr explains on my approach to accomplish selecting a default dropdown value. Basically, I have a service which would return the dropdown values [hard coded to test]. I was not able to select the value by default and almost spend a day and finally figured out that I should have set $scope.proofGroupId = "47"; instead of $scope.proofGroupId = 47; in the script.js file. It was my bad and I did not notice that I was setting an integer 47 instead of the string "47". I retained the plnkr as it is just in case if some one would like to see. Hopefully, this would help some one.
<select ng-init="somethingHere = options[0]" ng-model="somethingHere" ng-options="option.name for option in options"></select>
This would get you desired result Dude :) Cheers
Some of the scenarios, object.item would not be loaded or will be undefined.
Use ng-init
<select ng-init="object.item=2" ng-model="object.item"
ng-options="item.id as item.name for item in list"
$scope.item = {
"id": "3",
"name": "ALL",
};
$scope.CategoryLst = [
{ id: '1', name: 'MD' },
{ id: '2', name: 'CRNA' },
{ id: '3', name: 'ALL' }];
<select ng-model="item.id" ng-selected="3" ng-options="i.id as i.name for i in CategoryLst"></select>
we should use name value pair binding values into dropdown.see the
code for more details
function myCtrl($scope) {
$scope.statusTaskList = [
{ name: 'Open', value: '1' },
{ name: 'In Progress', value: '2' },
{ name: 'Complete', value: '3' },
{ name: 'Deleted', value: '4' },
];
$scope.atcStatusTasks = $scope.statusTaskList[0]; // 0 -> Open
}
<select ng-model="atcStatusTasks" ng-options="s.name for s in statusTaskList"></select>
I could help you out with the html:
<option value="">abc</option>
instead of
<option value="4">abc</option>
to set abc as the default value.

Resources