Difference with use of using Select as in ng-options - angularjs

Select box in IE is causing a problem in the opening for the first time when used with
identity as identity.identityName for identity in identityProofList track by identity.identityId or ng-repeat
but when used without identity as, it is working fine and can not see any difference in the functionality of select box also.
<select name="identityProof" ng-model="identityProof" ng-change="changeProofOfIdentity(identityProof)" ng-options="identity.identityName for identity in identityProofList track by identity.identityId" id="identityProofList" >
Where identityProofList is array of objects having properties identityName and identityId.
What is difference b/w the both?
Why ng-repeat is causing problem with IE11.

What is difference b/w the both?
Do you mean the difference between ng-repeat and ng-options?
The difference between using them to create DropdownList is that:
Dropdowns made with ng-options allows the selected value to be an object, while dropdowns made from ng-repeat has to be a string.
More details, check the AngularJS Select Boxes.
Why ng-repeat is causing problem with IE11 is also with using .
According to your codes, I create a sample using the following code, it works well on my IE browser (11.17134.1.0), you could refer to it.
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<p>Select a identity:</p>
<select ng-model="selectedidentity">
<option ng-repeat="x in identityProofList " value="{{x.identityId}}">{{x.identityName}}</option>
</select>
<h1>You selected: {{selectedidentity}}</h1><br />
<select name="identityProof" ng-model="identityProof" ng-change="changeProofOfIdentity(identityProof)"
ng-options="identity as identity.identityName for identity in identityProofList track by identity.identityId"
id="identityProofList"></select>
<h1>You selected: {{selectedvalue}}</h1>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function ($scope) {
$scope.identityProofList = [
{ identityId: "1001", identityName: "Admin" },
{ identityId: "1002", identityName: "User" },
{ identityId: "1003", identityName: "Customer" }
];
$scope.selectedvalue = "";
$scope.changeProofOfIdentity = function (identity) {
$scope.selectedvalue = identity.identityName;
}
});
</script>
The result like this.

Related

ng-init does not initialize my selected model

I have a select option where I get a list of titles i.e. Mr, Mrs, Dr etc. from an API, the code looks like this in the front end:
<select class="form-control" name="titleSelect" id="titleSelect" ng-options="option.value for option in titleData.availableOptions track by option.key" ng-model="adult[$index].selectedTitle" ng-init="adult[$index].selectedTitle = titleData.availableOptions[0]"></select>
And this in the controller:
var getPassengerTitle = PassengerDetailsAndCardDetailsService.getPassengerTitle();
PassengerDetailsAndCardDetailsService is service, where I get the API data i.e. the title data. Furthermore this service returns a promise.
This is where I set the title Data:
getPassengerTitle.then(function(result){
$scope.availableTitles = angular.fromJson(result.titleList);
$scope.tempListOfTitles = [];
for(var key in $scope.availableTitles){
$scope.tempListOfTitles.push({key : key, value : $scope.availableTitles[key]});
};
$scope.titleData = {
availableOptions: $scope.tempListOfTitles,
};
});
When I try to ng-init to the first option (that is Mr.) it does not work as in a blank option is shown. However when I tried statically defining the titleData in an object it works, could you please help me?
UPDATE:
I failed to mention that the title data is inside an ng-repeat to support input for multiple people/passengers in this case. Therefore I'm using adult[$index] where it creates an ng-model for each person/passenger.
I am not sure if this is the required behavior you want, but if you want to initialise the title on selecting an option you can either use the value from ng-model or use the event handler ng-change. Here is an example jsbin which handles the change and assigns the new value to ng-model. Let me know if this is what you were looking for
try like this.
var myapp = angular.module('app', []);
myapp.controller('Main', function ($scope) {
var vm = this;
vm.adult = {
'selectedTitle':'1'
};
vm.titleData = [
{'key':'0','value':'Mr'},
{'key':'1','value':'Ms'},
{'key':'2','value':'Dr'}
];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app = "app">
<div ng-controller="Main as ctrl">
<div class="select-style">
<select ng-options="option.key as option.value for option in ctrl.titleData" ng-model="ctrl.adult.selectedTitle"></select>
</div>
</div>
</div>

Selection on selectbox in IE when modifying the options with angular

I'm developping an application that use Angular and we want to synchronize two selectbox (HTML). It means when I click a value in the first selectbox , I want value in the second selectbox updated, and clickable too.
I did the following plunker to explain our problem:
http://plnkr.co/edit/KkBVcu29CZ6Elr741ZPe?p=preview
<html ng-app="myApp">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.min.js" type="text/javascript"></script>
<script>
'use strict';
angular.module("myApp", []).run(function($rootScope) {}).config(function () {});
angular.module('myApp').controller('myCtrl', function(
$scope) {
//$scope.obj2Selected = null;
$scope.list1 = [];
$scope.list1.push({
id : "1",
name : "1",
selected : false
});
$scope.list1.push({
id : "2",
name : "2",
selected : false
});
$scope.list1.push({
id : "3",
name : "3",
selected : false
});
$scope.list2 = [];
$scope.list2 .push({
id : "1",
name : "1"
});
$scope.list2.push({
id : "2",
name : "2"
});
$scope.list2.push({
id : "3",
name : "3"
});
$scope.selectionObjDone = function(){
$scope.obj2Selected = null;
$scope.list2.length = 0;
$scope.list2.push({
id : Math.random().toString(),
name : Math.random().toString()
});
$scope.list2.push({
id : Math.random().toString(),
name : Math.random().toString()
});
};
});
</script>
<div ng-controller="myCtrl">
<select size="10" id="listNodes" style="width:200px;"
ng-options="obj as obj.name for obj in list1 track by obj.id" ng-model="objSelected"
ng-change="selectionObjDone()">
</select>
<select size="10" style="width:200px;" id="select2"
ng-options="obj as obj.name for obj in list2 track by obj.id"
ng-model="obj2Selected" >
</select>
</div>
</html>
In this plunker everything looks fine. But if you copy/paste the exact same code in a test.html for example, opening it in IE (V11), you'll see the problem:
Start by clicking on the first selectbox to choose an option or another.
Try to select then an option in the second selectbox, you'll see that the selection is no more possible.
It works well in FF or Chrome, and also it works better on Plunker, even if sometimes it stops to work in Plunker (I did not find the exact use case).
It has a real link to the fact that I empty the array that is used to fill the 2nd selectbox. If I comment this line, everything work fine:
$scope.list2.length = 0;
I tried different ways to empty this array:
How do I empty an array in JavaScript?
Does anybody have an idea on what happens here and how to fix this?
Thanks
Finally, even with an expert of Angular we did not find the answer, but waiting a few, the new version of Angular (1.5.7) resolved by magic the problem!

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.

How to set a default value to ng-options (multiple select)

I wanted to set a default value to my ng-options by using ng-init, ng-model, etc. They didn't work at all. My code is following:
Angular
var app = angular.module('role', []);
app.controller('fooController', function($scope){
$scope.roles = [{id:1, name:"Administrator"}, {id:2, name: "Student"}];
$scope.user.roles = $scope.roles[0];
});
HTML
<body data-ng-app="role" data-ng-controller="fooController">
<select multiple class="form-control" data-ng-model="user.roles" data-ng-options="role.name for role in roles" required=""></select>
</body>
Here is my Plunkr.
Any help would be appreciated.
Update:
If you want to get directly to the reference used in this answer, here it is:
Reference:
Initial Selection In AngularJS ng-options with track by
Here's what worked for me:
app.controller('fooController', function($scope){
$scope.roles = [{id:1, name:"Administrator"}, {id:2, name: "Student"}];
$scope.user = {};
$scope.user.roles = [ $scope.roles[0] ];
});
There was an error in the plunk that user wasn't initialized, apart from this, Angular would compare every object in the ng-options array to every element in the ng-model array. JavaScript comparison not Angular comparison, comparing 2 objects even with same properties in JavaScript returns false (different objects).
Plunk: http://plnkr.co/edit/ccsAVvPACnN6Qzje7HcB?p=preview
.
Now, this is not ideal. Typically you want to correlate these based on ID or so, here's another way:
In HTML, use track by to tell AngularJS to compare IDs instead of entire objects:
<select multiple class="form-control"
data-ng-model="user.roles"
data-ng-options="role.name for role in roles track by role.id"
required=""></select>
Then in your controller, you can use any object without actually being in the array:
app.controller('fooController', function($scope){
$scope.roles = [{id:1, name:"Administrator"}, {id:2, name: "Student"}];
$scope.user = {};
$scope.user.roles = [ {id:1, name:"Administrator"} ];
});
Plunk: http://plnkr.co/edit/NKLXrwqwk36YfhBSXILN?p=preview
Note that I didn't even need the name property. It's just for making a proper object later, but it really isn't needed for matching now, try without it!
.
I wrote a detailed tutorial with an accompanying video on this initial selection problem and its variations. It's focused on single-select but multi-select is just using an array of objects instead of one object directly.
Check it out for more understanding -- highly recommended:
Initial Selection In AngularJS ng-options with track by
.
Let me know in comments if you are still struggling with this.
if your model is like $scope.user.roles = [1]; then your ng-options should be like this,
data-ng-options="role.id as role.name for role in roles"
this will select only the ID
if you do like data-ng-options="role.name for role in roles" then your model should be like
$scope.user.roles = [{id:1, name:"Administrator"}];
because this will select the whole object
and in your controller
$scope.user = {}; //this line should be add
because your trying to access a roles property of user but there is no user object defined, this will also occur a error
here is the Updated Plunker
here is the updated plunker1 plunker2 for your case of ng-options
you can use ng-init here. please check.
like this
<body ng-init="role.name = roles[0].name" data-ng-app="role" data-ng-controller="fooController">
<select multiple class="form-control" data-ng-model="user.roles" data-ng-options="role.name for role in roles" required=""></select>
</body>
Your Plunkr has errors. You have to define $scope.user = {}; before you use it. Then it will work.
Note: This will only set an initial value to model. If you want to make Administrator highlighted by default, you'll have to figure out some other way.

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>

Resources