Angularjs select multiple options from object - angularjs

Trying to select multiple options in angularjs regarding to object values
Here is a code:
myapp.controller('myctrl', [
'$scope',
function ($scope) {
$scope.query = {
Statuses: {
Draft: true,
Live: true,
Pending: true,
Archived: false,
Deleted: false
}
};
}
]);​
And html
<div ng-controller="myctrl">
<select multiple>
<option value="Draft" ng:model="query.Statuses['Draft']">Draft</option>
<option value="Pending" ng:model="query.Statuses.Pending">Pending</option>
<option value="Live" ng:model="query.Statuses.Live">Live</option>
<option value="Archived" ng:model="query.Statuses.Archived">Archived</option>
<option value="Deleted" ng:model="query.Statuses.Deleted">Deleted</option>
</select>
{{query | json}}
</div>
(Non)working sample on jsfiddle​
http://jsfiddle.net/andrejkaurin/h9fgK/

Using a model for statuses ($scope.statuses), and ng-options to iterate over them:
function MyCtrl($scope) {
$scope.statuses = [ 'Draft', 'Pending', 'Live', 'Archived', 'Deleted' ];
$scope.selectedStatuses = [ 'Pending', 'Live' ];
}​
.
<select ng-model="selectedStatuses" multiple ng-options="status for status in statuses">
</select>

You're trying to use a select multiple like a checkbox list, which is a little strange. Multi-selects output an array. You can't put ng-model on an option tag like that, it goes on the select itself. So since the select will output an array of values, you'll need to loop through the values and update the nodes in your scope.
Here's a plunk demonstrating the code
And here's the code:
JS
function inArray(x, arr) {
for(var i = 0; i < arr.length; i++) {
if(x === arr[i]) return true;
}
return false;
}
app.controller('MainCtrl', function($scope) {
$scope.query = {
Statuses: {
Draft: true,
Live: true,
Pending: true,
Archived: false,
Deleted: false
}
};
$scope.selectionsChanged = function(){
for(var key in $scope.query.Statuses) {
$scope.query.Statuses[key] = inArray(key, $scope.selectedValues);
}
};
});
HTML
<select multiple ng-model="selectedValues" ng-change="selectionsChanged()">
<option value="Draft" ng-selected="query.Statuses.Draft">Draft</option>
<option value="Pending" ng-selected="query.Statuses.Pending">Pending</option>
<option value="Live" ng-selected="query.Statuses.Live">Live</option>
<option value="Archived" ng-selected="query.Statuses.Archived">Archived</option>
<option value="Deleted" ng-selected="query.Statuses.Deleted">Deleted</option>
</select>
<br/>
{{query | json}}
I hope that helps.

Here is an alternate to blesh solution
app.controller('MainCtrl', function($scope) {
$scope.query = {
Statuses: ["Pending","Live"]
};
});
And select
<select multiple ng:model="query.Statuses" >
<option value="Draft">Draft</option>
<option value="Pending">Pending</option>
<option value="Live">Live</option>
<option value="Archived">Archived</option>
<option value="Deleted">Deleted</option>
</select>
{{query | json}}
Working sample is here:
http://plnkr.co/edit/bCLnOo

Just to point out, IMO multiple select elements are a UI interaction evil. Touch anything without remembering to hold down modifier keys, which some users don't know about, and you lose the whole selection. Especially bad if there enough options that they're not all visible, then you can't even tell when you're dropping an existing selection. Multiple checkboxes are a much better way to represent the same possible options and current selection. A container's worth of them can be made scrollable, effectively similar to a multi-select with more options than size. (Not an answer I know...)

Related

Retrieve Selected Option Value From HTML DropDownList

I've a DropDownList where user has to select options and save it to database. I am using the following with AngularJs:
<select>
<option>----Please Select Sub-Category----</option>
<option ng-repeat="m in Categories" value="{{ m.CategoryId }}" ng-model="saveProducts.CategoryId">{{ m.Category }}</option>
</select>
I can show the values in the above DropDownList but stuck to retrieve the value from the selected and pass it to the scope. I've tried even this, a silly one:
<select>
<option>----Please Select Sub-Category----</option>
<option ng-repeat="m in Categories" value="{{ m.CategoryId }}" ng-model="m.CategoryId">{{ m.Category }}</option>
</select>
But that will not work. saveProducts is the object (scope) where I am passing values but is there any easy way where I can pass option value with the above procedure?
Here what I am doing to save data in database and it works fine except the option value, it's unable to retrieve values with the above:
productApp.controller('addProductController', function ($scope, $http) {
$scope.addData = function () {
$http({
method: 'POST',
url: '/Product/AddProductsToDb',
data: $scope.saveProducts
}).success(function () {
$scope.saveProducts = null;
}).error(function () {
alert('Failed');
});
}
});
This is the output I have and just want to pass the option value from it:
Update 1 - This is what I've tried but I can show the value in the alert method using as follows:
<select ng-model="saveProducts.ParentId"
ng-options="m.Category for m in Categories track by m.CategoryId">
<option value="">----Please Select Sub-Category----</option>
</select>
AngularJs Controller:
productApp.controller('addProductController', function ($scope, $http) {
$scope.addData = function () {
angular.forEach($scope.saveProducts, function (model, index) {
$scope.saveProducts.ParentId = (model.CategoryId);
});
alert($scope.saveProducts.ParentId);
$http({
method: 'POST',
url: '/Product/AddProductsToDb',
data: $scope.saveProducts
}).success(function () {
$scope.saveProducts = null;
}).error(function () {
alert('Failed');
});
}
});
Note: It saves TextBox input value but stuck with DropDownList. Unable to retrieve select option value and save it to database.
You should have a property to store the selected option. You can use ng-options to render the dropdown.
<select ng-model="selectedCategory"
ng-options="option.Category for option in Categories track by option.CategoryId ">
<option value="">Select Option</option>
</select>
Now your select element's ng-model is set to selectedCategory. So in your add method you can access that and use that for saving.
$scope.addData = function () {
console.log($scope.selectedCategory);
//to do : use selectedCategory
}
Use ngOptions. Depending on the structure of your Categories data, you could do something like:
<select ng-options="m as m.yourProperty for m in Categories" ng-model="selected"></select>
Then, in Angular...
$scope.selected = $scope.Categories[0];
Read the ngOptions documentation to tweak according to your needs.

Responding to drop down selection change in angular without model binding

I have a drop down that should cause a data fetch on change. I don't need two way binding to a model for the drop down. I just want it initially populated with a list of departments and when a user selects one, it gets the list of users in that department.
The select looks like this:
<select class="form-control" id="selDepartmentList" ng-model="departmentList" ng-change="getUsersInDepartment(document.getElementById("selDepartmentList").options[document.getElementById("selDepartmentList").selectedIndex].value)">
<option value="-1">All</option>
<option ng-repeat="dept in departmentList"
value="{{dept.DepartmentId}}">
{{dept.DepartmentName}}
</option>
</select>
I tried ng-change without ng-model, but it fails since ng-change requires ng-model for some reason. I tried setting ng-model to null and empty string, but neither worked. I also tried not using ng-change at all and using onchange, but getUsersInDepartment can't be found through onchange since it's attached to my controller. With ng-model set to departmentList, the drop down won't hold a value, any selection is erased.
All I want to have happen is that when a user selects a department it passes the id for that department to getUsersInDepartment, which will then fetch the user list. But right now getUsersInDepartment is never called.
departmentList is defined in my controller and attached to $scope. All the examples I've seen have some kind of selectedModelObject that they bind to the drop down. I don't have one of those.
My controller looks like:
controller('AdminTableCtrl', function ( $scope, coreAPIservice ) {
$scope.userList = [];
$scope.departmentList = [];
coreAPIservice.GetUserList().success(function (response) {
$scope.userList = response;
});
coreAPIservice.GetDepartmentList().success(function (response) {
$scope.departmentList = response;
});
$scope.getUsersInDepartment = function(deptId) {
if(deptId === -1) {
coreAPIservice.GetUserList().success(function (response) {
$scope.userList = response;
});
}
else {
coreAPIservice.GetUsersInDepartmentList(deptId).success(function (response) {
$scope.userList = response;
});
}
}
});
Edit:
My original attempt with ng-options:
<select class="form-control" id="selDepartment"
ng-model="selectedDepartment"
ng-options="dept as dept.DepartmentName for dept in departmentList track by dept.DepartmentId">
<option value="">Select Team...</option>
</select>
selectedDepartment is defined as:
$scope.selectedDepartment = {};
The solution is to avoid decorating the <select> element with any angular directives and instead place ng-click on each <option>.
Like this:
<select class="form-control" id="selDepartmentList">
<option value="-1" selected>All</option>
<option ng-repeat="dept in departmentList"
ng-click="getUsersInDepartment(dept.DepartmentId)"
value="{{dept.DepartmentId}}">
{{dept.DepartmentName}}
</option>
</select>
Making a custom directive should work for this problem.
angular
.module('my_module')
.directive('ngCustomChange', function($parse) {
return function(scope, element, attrs) {
var fn = $parse(attrs.ngCustomChange);
element.bind('change', function(event) {
scope.$apply(function() {
event.preventDefault();
fn(scope, {$event:event});
});
});
};
});
<select ng-custom-change="$ctrl.myFunction()">
<option value="1">Value 1</option>
<option value="2">Value 2</option>
</select>

Using ng-if inside ng-options to filter null results

I'm trying to filter out "null" results from a select dropdown list.
Until now I was using just regular html <select> + <option> with ng-repeat and excluding null result this way:
<option ng-repeat="person in showCase.persons" ng-if="person.profiles">
{{person.profiles}}
</option>
This way I could get a list without empty/null 'user profile'.
Now I started using ng-options instead because the list includes arrays with objects,
but I can't get the null results out - ..when I'm using ng-if the whole <select> disappears :
<select ng-model="profile_filter" ng-options="person.profiles for person in persons"
ng-if="person.profiles">
</select>
My priority was doing it inline and not in my controller because there's many <select> objects in the page, and some do require the "null" results to show.
I know, it's a very basic question, but still it got me stuck for the last 2 hours.
Thanks.
When you use ng-if on the select it is on the select looking for a property on the scope person.profiles which is not there. person.profiles for person in persons is a mere expression for ng-options.
You could just filter out nulls from the controller itself before binding it. Or create a filter or just use a filter expression with the existing angular core filter.
Example:-
In your controller define a function on the scope to remove if profiles is falsy (You can make it explicit as you need), if you return truthy then the item will be added as option else it will be ignored:
$scope.removeNull = function(itm) {
return itm.profiles;
}
And just use it in the view:-
<select ng-model="profile_filter"
ng-options="person.profiles for person in persons|filter:removeNull">
angular.module('app', []).controller('ctrl', function($scope) {
$scope.persons = [{
profiles: null
}, {
profiles: "prf1"
}, {
profiles: "prf2"
}, {
profiles: "prf3"
}, {
profiles: null
}, {
profiles: "prf4"
}]
$scope.removeNull = function(itm) {
return itm.profiles;
}
$scope.profile_filter = $scope.persons[1];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<select ng-model="profile_filter" ng-options="person.profiles for person in persons|filter:removeNull">
</select>
{{profile_filter}}
</div>
Try with ng-if="person.profiles!=null" to get a boolean value.

Move from final 1.3 rc to 1.3.0 - <select> option problems after <select> bug fixes made in the move

My application has this HTML:
<select id="contentTypeSelect"
ng-change="home.configChanged(true)"
ng-model="ctrl.configService.admin.contentTypeId"
ng-options="item.id as item.name for item in content"></select>
Here is the value of content:
var content =
[{"id":0,"name":"*"},
{"id":1,"name":"Menu"},
{"id":2,"name":"Service"},
{"id":3,"name":"Help"},
{"id":4,"name":"Product"},
{"id":5,"name":"Version"},
{"id":6,"name":"Exam"},
{"id":7,"name":"Track"}]
My problem is that it creates a select with a blank entry:
<select id="contentTypeSelect"
ng-change="home.configChanged(true)"
ng-model="ctrl.configService.admin.contentTypeId"
ng-options="item.id as item.name for item in content"
class="ng-pristine ng-untouched ng-valid">
<option value="? string: ?">
</option><option value="0" selected="selected">*</option>
<option value="1">Menu</option>
<option value="2">Service</option>
<option value="3">Help</option>
<option value="4">Product</option>
<option value="5">Version</option>
<option value="6">Exam</option>
<option value="7">Track</option>
</select>
Can someone help explain to me why this line is in the HTML:
<option value="? string: ?">
Here is how I am populating the select data:
self.content = results[2];
self.configService.admin.contentTypeId = self.content[0].id;
First I populate the data in self.content and then I set the modal to the id of the first element of that array.
Note this is only a problem with the production 1.3 release. I am not seeing this problem with that beta.
> #license AngularJS v1.3.0-beta.8 // This release is working for me
> #license AngularJS v1.3.0-rc.3 // This release is working for me
> #license AngularJS v1.3.0-rc.5 // This release is working for me
> #license AngularJS v1.3.0 // This release is failing for me
I assume now that this change is the result of the following change made between rc5 and the production release:
1.3.0 superluminal-nudge (2014-10-13)
Bug Fixes
select:
add basic track by and select as support (addfff3c, #6564)
manage select controller options correctly (2435e2b8, #9418)
I will look into this. Hopefully the bug fix did not introduce a new bug that I am facing. Certainly my code now appears to work in all versions prior to 1.3.0
Please note the order that my application works.
a) Open the HTML
b) Get the data for the select list (takes 5 seconds)
c) Populate ng-options
d) Populate ng-model
Could this be a problem related to the bug fix that was added just before the release of 1.3.0 to the options. My same code has been working for a year now and suddenly is giving me this problem ONLY with the latest 1.3.0 release.
This seems to be a known bug with v1.3.0 (see: https://github.com/angular/angular.js/issues/9714 and https://github.com/angular/angular.js/issues/9691).
The bug is in someway triggered by an async assignment of ngOptions model data and pre-selecting a value with a falsy identifier (e.g. '' or 0). It can be reproduced as follows:
(function (app, ng) {
'use strict';
app.controller('AppCtrl', ['$timeout', function($timeout) {
var vm = this;
$timeout(function () {
vm.content = [
{ id: 0, name: 'A' },
{ id: 1, name: 'B' },
{ id: 2, name: 'C' }
];
}, 1000);
}]);
}(angular.module('app', []), angular));
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0/angular.min.js"></script>
<div data-ng-app="app">
<!-- wrong behavior -->
<div data-ng-controller="AppCtrl as app1" data-ng-init="app1.selected = 0;">
<select
data-ng-model="app1.selected"
data-ng-options="item.id as (item.name + ' [' + item.id + ']') for item in app1.content"
size="4"
></select>
</div>
<!-- correct behavior -->
<div data-ng-controller="AppCtrl as app2" data-ng-init="app2.selected = 1;">
<select
data-ng-model="app2.selected"
data-ng-options="item.id as (item.name + ' [' + item.id + ']') for item in app2.content"
size="4"
></select>
</div>
</div>
This additional option results from no item beeing selected by default. If you set ctrl.configService.admin.contentTypeId to a valid ID from your list of items that one will be selected and you will no longer see this additional option with value ?
So this results from either no selection was defined or there is an error and the selected item can not be determined
Update:
I changed the AngularJS version to 1.3 and it still behaves as expected
Update2:
Eventually you should propagate the new value of self.configService.admin.contentTypeId by calling $scope.apply()?
Update3:
Added an async function for simulating getting data from service.
Without calling $apply() there is no way for Angular to know that any of the $scope values have changed since there are no events which can trigger an update. So you have to tell Angular that you changed some value. You can see this if you remove the $apply() call, then event the simple message text does not get updated.
Update4:
Changed setTimeout to $timeout since then $apply() is not required liks Yoshi explained.
Example:
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', function ($scope, $timeout) {
$scope.status = 'loading...';
$scope.getData = function () {
$timeout(function () {
$scope.selectedItem = 0;
$scope.content =
[{ "id": 0, "name": "*" },
{ "id": 1, "name": "Menu" },
{ "id": 2, "name": "Service" },
{ "id": 3, "name": "Help" }]
$scope.status = 'Call done!';
}, 1000);
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="MyCtrl" ng-init="getData()">
<label>Status: {{status}}</label><br/>
<select ng-model="selectedItem" ng-options="item.id as item.name for item in content"></select>
</div>
</div>

angularjs remove duplicate values from ngrepeat

I am trying to get a category dropdown list fetched from below JSON data. I have same category multiple times, For Ex: Computer
[
{
"title":"C Programming",
"category":"Computer"
},
{
"title":"International Tax",
"category":"Business"
},
{
"title":".net Programming",
"category":"Computer"
}
//more data...
]
AngularJS:
function showSubjects($scope, $http)
{
$http({method: 'POST', url: 'js/subjects.json'}).success(function(data)
{
$scope.items= data; // response data
});
}
HTML:
<div id="ng-app" ng-app ng-controller="showSubjects">
<select>
<option ng-repeat="subjects in items">{{subjects.category}}</option>
</select>
</div>
I want to display duplicate categories only once. Please give me some suggestions, how to acheive the required output. Thanks in advance.
Use
<option ng-repeat="subjects in items | unique:'category'">{{subjects.category}}</option>
Look here for more: Unique & Stuff
You can use your own function like below:
<select name="cmpPro" ng-model="test3.Product" ng-options="q for q in productArray track by q">
<option value="" >Plans</option>
</select>
productArray =[];
angular.forEach($scope.leadDetail, function(value,key){
var index = $scope.productArray.indexOf(value.Product);
if(index === -1)
{
$scope.productArray.push(value.Product);
}
});

Resources