How to use ng-options in array with objects - angularjs

I have a data source that looks like this:
var categories =
[{
{"name":"First Category","subcats":[
{"name":"Sub Category 1"},
{"name":"Sub Category 2"},
{"name":"Sub Category 3"}]
},{
{"name":"Second Category","subcats":[
{"name":"Sub Category 1"},
{"name":"Sub Category 2"},
{"name":"Sub Category 3"}]
}]
I couldn't figure out how to use ng-options to show sub categories grouped by main category. Result should look like this:
<select>
<optgroup>First Category
<option>Sub Category 1</option>
<option>Sub Category 2</option>
<option>Sub Category 3</option>
</optgroup>
<optgroup>Second Category
<option>Sub Category 1</option>
<option>Sub Category 2</option>
<option>Sub Category 3</option>
</optgroup>
</select>

1) Fix your categories array;
2) Flatten it to use with ngOptions and group by.
Example:
angular.module('plunker', [])
.controller('MainCtrl', function($scope) {
var categories =
[
{
"name": "First Category",
"subcats": [
{"name": "Sub Category 1"},
{"name": "Sub Category 2"},
{"name": "Sub Category 3"}
]
},
{
"name": "Second Category",
"subcats": [
{"name": "Sub Category 1"},
{"name": "Sub Category 2"},
{"name": "Sub Category 3"},
{"name": "Sub Category 4"}
]
}
];
$scope.options = [];
angular.forEach(categories, function (category){
angular.forEach(category.subcats, function (subCat){
subCat.categoryName = category.name;
$scope.options.push(subCat);
});
});
});
<script src="https://code.angularjs.org/1.6.2/angular.js" ></script>
<html ng-app="plunker">
<body ng-controller="MainCtrl">
<select ng-model="test.model"
ng-options="option.name group by option.categoryName for option in options">
</select>
</body>
</html>

this.categories =
[
{
"name": "First Category",
"subcats": [
{ "name": "Sub Category 1" },
{ "name": "Sub Category 2" },
{ "name": "Sub Category 3" }]
},
{
"name": "Second Category",
"subcats": [
{ "name": "Sub Category 4" },
{ "name": "Sub Category 5" },
{ "name": "Sub Category 6" }]
}
];
and in template:
<select>
<optgroup *ngFor="let category of categories;" label="{{category.name}}">
<option *ngFor="let sub of category.subcats;">{{sub.name}}</option>
</optgroup>

Related

angular js filter inside ng-change

my data template looks like this,
scope.items=[{"name:"John","score":1},{"name":"Rick","score":5},{"name":"Peter","score":2}]
I have a select box with values 0,1,2,3,4,5 and would like to filter items object based on score value selected in dropdown
scope.scores= [
{
"name":"condition 0",
"value":"0"
},
{
"name":"condition 1",
"value":"1"
},
{
"name":"condition 2",
"value":"condition 2"
},
{
"name":"condition 3",
"value":"3"
},
{
"name":"condition 4",
"value":"4"
},
{
"name":"condition 5",
"value":"5"
}
]
HTML
<select id="scoreS" ng-model="score" ng-change="updateScore()">
<option
ng-repeat="score in scores"
value="{{score.value}}">{{score.name}}</option>
</select>
So when i select condition 0 from my dropdown box I need to filter items to show only those objects matching score(key) 0 and when I select 1 from the drop down , match only items having score(key) 1 and so on. how do you do this inside updateScore() function ?
Try like this. it's better use ng-options instead of ng-repeat in drop-down
var app = angular.module('anApp', []);
app.controller('aCtrl', function($scope) {
$scope.items=[
{"name":"John","score":1}
,{"name":"Rick","score":5}
,{"name":"Peter","score":2}
]
$scope.scores= [
{
"name":"condition 0",
"value":"0"
},
{
"name":"condition 1",
"value":"1"
},
{
"name":"condition 2",
"value":"2"
},
{
"name":"condition 3",
"value":"3"
},
{
"name":"condition 4",
"value":"4"
},
{
"name":"condition 5",
"value":"5"
}
]
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
<div ng-app="anApp" ng-controller="aCtrl as vm">
<select id="scoreS" ng-model="score" ng-options="score.value as score.name for score in scores ">
</select>
<div ng-repeat="item in items| filter:{score:score}">
<span>{{item.name}}</span>
</div>
</div>
use filter option to filter the data according to drop down
<div ng-repeat="item in items | filter :score">
Demo
angular.module("app",[])
.controller("ctrl",function($scope){
$scope.scores= [
{
"name":"condition 0",
"value":"0"
},
{
"name":"condition 1",
"value":"1"
},
{
"name":"condition 2",
"value":"2"
},
{
"name":"condition 3",
"value":"3"
},
{
"name":"condition 4",
"value":"4"
},
{
"name":"condition 5",
"value":"5"
}
]
$scope.items=[{"name":"John","score":1},{"name":"Rick","score":5},{"name":"Peter","score":2}]
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<select id="scoreS" ng-model="score" ng-change="updateScore()">
<option ng-repeat="score in scores" value="{{score.value}}">{{score.name}}</option>
</select>
<div ng-repeat="item in items | filter :score">
{{item.name}}= {{item.score}}
</div>
</div>

Track by index doesnt reset after changing selection

i have a cascading select option, and is working well, the problem is that when i change the first selected option, in the second selection option (subcategory), it keeps the index. So case i change the category (first select), in the second selection it goes to the option position that it was.
For better understanding, please check this example i made and try changin the options. You will notice that in the second selec option keeps the position index that had in the previous category selected. It doesnt starts to 0 when changing the category.
Link: http://jsfiddle.net/Fqfg3/28/
Js:
var app = angular.module('app', []);
app.controller('PeopleCtrl', function ($http,$scope) {
vm = this;
vm.options = [
{
"_id": "1",
"label": "Category 1",
"childs": [
"Category 1 -> Subcategory 1",
"Category 1 -> Subcategory 2",
"others"
]
},
{
"_id": "2",
"label": "Category 2",
"childs": [
"Category 2 -> Subcategory 1",
"Category 2 -> Subcategory 2",
"others"
]
},
{
"_id": "3",
"label": "Category 3",
"childs": [
"Category 3 -> Subcategory 1",
"Category 3 -> Subcategory 2",
"others"
]
}];
});
html:
<div ng-app="app" ng-controller="PeopleCtrl as ctrl" class="container">
{{ctrl.options}}
<div class="form-group question-wrapper">
<select class="form-control"
name="category"
ng-options="option.label for option in ctrl.options track by option._id"
ng-model="ctrl.supportMail.selected">
</select>
</div>
<div class="form-group question-wrapper">
<select id="sub" class="form-control"
name="subcategory"
>
<option ng-repeat="child in ctrl.supportMail.selected.childs track by $index">{{child}}</option>
</select>
</div>
</div>
You can use ng-change in main select to reset the subselect to default.
Here's is a demonstration working:
(function() {
"use strict";
angular.module('app', [])
.controller('mainCtrl', function() {
var vm = this;
vm.options = [
{
"_id":"1",
"label":"Category 1",
"childs":[
"Category 1 -> Subcategory 1",
"Category 1 -> Subcategory 2",
"others"
]
},
{
"_id":"2",
"label":"Category 2",
"childs":[
"Category 2 -> Subcategory 1",
"Category 2 -> Subcategory 2",
"others"
]
},
{
"_id":"3",
"label":"Category 3",
"childs":[
"Category 3 -> Subcategory 1",
"Category 3 -> Subcategory 2",
"others"
]
}
];
vm.reset_subSelect = function() {
vm.supportMail.child = vm.supportMail.selected.childs[0];
}
});
})();
<!DOCTYPE html>
<html ng-app="app">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js" type="text/javascript"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" type="text/javascript"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.min.js"></script>
</head>
<body ng-controller="mainCtrl as ctrl">
<div class="container">
<div class="form-group question-wrapper">
<select class="form-control" name="category" ng-options="option.label for option in ctrl.options track by option._id" ng-model="ctrl.supportMail.selected" ng-change="ctrl.reset_subSelect()" ng-init="ctrl.supportMail.selected = ctrl.options[0]">
</select>
</div>
<div class="form-group question-wrapper">
<select class="form-control" id="sub" name="subcategory" ng-options="child for child in ctrl.supportMail.selected.childs" ng-model="ctrl.supportMail.child" ng-init="ctrl.supportMail.child = ctrl.supportMail.selected.childs[0]">
</select>
</div>
</div>
</body>
</html>
I hope it helps.
By adding an ng-model to your subcategory I was able to resolve the issue you can see the example here
Hope this helps.

How to add multiple input box dynamically with dropdown in angularjs

I am having this problem which I can't find the solution to.
1) I have a dropdown list which the data is pull in from a json file
2) When the user selects a item I want to dynamically add a input box without a button.
Got a jQuery code but wanted to do it the angular way, but read that ng-Change is not the same as jquery .change?
Can anyone help or point me into the right direction of how to do this.
HTML
<div class="main-content__right" ng-controller="QuestionController">
<div ng-repeat="element in questionList">
<fieldset>
<div id="add-more" class="well">
<div class="field">
<div style="width:100%;" class="dropdown">
<select name="{{options.name}}" id="select" data-ng-model="formData"
data-ng-options="options as options.label for options in element.inputElement | orderBy:'label'"
ng-change="onCategoryChange(formData)">
<option value="" data-id="null" disabled="" selected="">Select an item...</option>
</select>
</div>
</div>
{{formData}}
</div>
</fieldset>
</div>
app.js
var app = angular.module("cab", []);
app.controller('QuestionController', function($scope) {
var $scope.formData = {};
$scope.questionList = [{
"sectionTitle": "Travel",
"subTitle": "How much do you spend on these items for your car?",
"inputType": "select",
"inputElement": [{
"label": "Public transport",
"name": "travelOutgoing",
"helpInfo": "include train journeys",
"type": "select"
}, {
"label": "Taxis",
"name": "travelOutgoing",
"type": "select"
}, {
"label": "Bicycle",
"name": "travelOutgoing",
"helpInfo": "general running costs such as repair or rental",
"type": "select"
}, {
"label": "Car rental",
"name": "travelOutgoing",
"helpInfo": "include fuel, parking charges and tolls",
"type": "select"
}
]
}];
$scope.onCategoryChange = function () {};
});
can be found on http://plnkr.co/edit/PPDYKjztPF528yli9FbN?p=preview
Your controller function needs to add each selection to an array on scope:
Controller
app.controller('QuestionController', function($scope) {
$scope.formData = [];
$scope.selectedValue = {};
$scope.questionList = [{
"sectionTitle": "Travel",
"subTitle": "How much do you spend on these items for your car?",
"inputType": "select",
"inputElement": [{
"label": "Public transport",
"name": "travelOutgoing",
"helpInfo": "include train journeys",
"type": "select"
}, {
"label": "Taxis",
"name": "travelOutgoing",
"type": "select"
}, {
"label": "Bicycle",
"name": "travelOutgoing",
"helpInfo": "general running costs such as repair or rental",
"type": "select"
}, {
"label": "Car rental",
"name": "travelOutgoing",
"helpInfo": "include fuel, parking charges and tolls",
"type": "select"
}]
}];
$scope.onCategoryChange = function(selectedItem) {
$scope.formData.push(selectedItem)
};
});
Then you can use an ng-repeat to render all of the items in formData.
HTML
<fieldset>
<div id="add-more" class="well">
<div class="field">
<div style="width:100%;" class="dropdown">
<select name="{{options.name}}" id="select" data-ng-model="selectedValue" data-ng-options="options as options.label for options in element.inputElement | orderBy:'label'" ng-change="onCategoryChange(selectedValue)">
<option value="" data-id="null" disabled="" selected="">Select an item...</option>
</select>
</div>
</div>
<div ng-repeat="item in formData track by $index">
<input ng-model="item.label" />
</div>
</div>
</fieldset>

angular group by while iterating records on select list

Let's say if I've data coming in JSON like this.
[
{
"id": 10,
"session": "test2",
"event": "Event 2"
},
{
"id": 11,
"session": "TEST 22",
"event": "Event 2"
},
{
"id": 9,
"session": "test 1",
"event": "Event 1"
}
]
I want to group the records by event, (Event 2 is repeated) and display a select box while keeping track of the id (on $scope so I can update the form).
Expectation.
<select>
<optgroup label="Event 1">
<option value="10">test2</option>
</optgroup>
<optgroup label="Event 2">
<option value="11">Test 22</option>
<option value="9">test 1</option>
</optgroup>
</select>
ng-options="opt.id as opt.session group by opt.event for opt in options"

How can we make dependent select boxes in select2 with angular?

I am using select2 with angularjs for select boxes in my application. There is one parent select box where user can select multiple groups and there are many other child select boxes with the same group selection feature.
My problem is how to restrict child group search options according to
parent group selected option. i.e. say if parent groups are Group1,
Group2, Group3 then the child group search box should avail the
options selected in parent groups only.
HTML:
<body ng-app="myModule">
<div ng-controller="myCtrl">
<div ng-repeat="activity in activities">
<br><br><br><br>
<div>
Parent Group:
<select multiple class="full-width" ui-select2="groupSetup" ng-model="activity.act_group_id" ng-init="activity.act_group_id=split_custom(activity.act_group_id,',',1)" data-placeholder="Select Group">
<option ng-repeat="group in groups | orderBy:'text'" value="{{group.id}}">{{group.text}}</option>
</select>
<p>selected parent groups {{activity.act_group_id}}</p>
</div>
<br><br>
<div>
Child Group:
<select multiple class="full-width" ui-select2="groupSetup" ng-model="activity.act_auto_approve_group" ng-init="activity.act_auto_approve_group=split_custom(activity.act_auto_approve_group,',',1)" data-placeholder="Select Group">
<option ng-repeat="group in groups | orderBy:'text'" value="{{group.id}}">{{group.text}}</option>
</select>
<p>selected child group {{activity.act_auto_approve_group}}</p>
</div>
</div>
</div>
</body>
JS:
var activityModule = angular.module('myModule', ['ui']);
activityModule.controller('myCtrl', ['$scope', '$http', function ($scope, $http) {
$scope.activities = [{"act_name": "activity1", "act_group_id": "62,68", "act_auto_approve_group": "62"}];
$scope.groups = [{"text": "Group1", "id": 2}, {"text": "Group2", "id": 62}, {"text": "Group3", "id": 68}, {"text": "Group4", "id": 74}, {"text": "Group5", "id": 98}, {"text": "Group6", "id": 104}, {"text": "Group7", "id": 107}, {"text": "Group8", "id": 139}, {"text": "Group9", "id": 149}, {"text": "Group10", "id": 154}];
$scope.groupSetup = {
multiple: true,
formatSearching: 'Searching the group...',
formatNoMatches: 'No group found'
};
// custom function to convert string into attay (string arra or integer array)
$scope.split_custom = function(string, spliter, is_integer) {
$scope.ret_arr = string.split(spliter); // convert string into array
if (is_integer==1)
$scope.ret_arr = $scope.ret_arr.map(Number); // convert string array into integer array
return $scope.ret_arr;
};
}]);
http://plnkr.co/edit/dpX7jNkEgRoPyRZpJV92?p=preview
After 6 hours struggle, I was able to achieve this using ng-change event in a tricky way:
HTML :
1.Parent select box:
<select ng-change="parent_group_changed(activity)" multiple class="full-width" ui-select2="groupSetup" ng-model="activity.act_group_id" ng-init="activity.act_group_id=split_custom(activity.act_group_id,',',1)" data-placeholder="Select Group" >
<option ng-repeat="group in groups" value="{{group.id}}">{{group.text}}</option>
</select>
2.Child select box:
<select multiple class="full-width" ui-select2="groupSetup" ng-model="activity.act_auto_approve_group" ng-init="activity.act_auto_approve_group=split_custom(activity.act_auto_approve_group,',',1)" data-placeholder="Select Group">
<option ng-repeat="group in activity.act_groups | orderBy:'text'" value="{{group.id}}">{{group.text}}</option>
</select>
JS
$scope.groups = [{"text": "Group1", "id": 2}, {"text": "Group2", "id": 62}, {"text": "Group3", "id": 68}, {"text": "Group4", "id": 74}, {"text": "Group5", "id": 98}, {"text": "Group6", "id": 104}, {"text": "Group7", "id": 107}, {"text": "Group8", "id": 139}, {"text": "Group9", "id": 149}, {"text": "Group10", "id": 154}];
$scope.groups2 = $scope.groups;
$scope.groupSetup = {
multiple: true,
formatSearching: 'Searching the group...',
formatNoMatches: 'No group found'
};
$scope.parent_group_changed = function(activity) {
activity.act_groups=[];
for(var i=0; i<activity.act_group_id.length; i++)
{
var x = activity.act_group_id[i];
activity.act_groups.push($filter('filter')($scope.groups2, {id:x})[0]);
}
};
Plunker
http://plnkr.co/edit/07Uj8EdDlAyT54AkuaRQ?p=info

Resources