AngularJS <select> ng-options selected value is not properly set - angularjs

I have this pseudo code angularjs app. You can select a hobby for each person, save it and load it again.
However when I load the data, the select boxes dont have the correct option selected. person.hobby exists and is the correct object, but it looks like ng-model isn't set correctly.
Am I missing something?
<div ng-repeat="person in people">
<p>{{ person.fullname }}</p>
<select ng-model="person.hobby"
ng-options="h.hobby_name group by h.category for h in hobbies">
</select>
</div>
<script>
//... controller...
$http.get('/gethobbies/').succes(data) {
hobbies = data;
};
$http.get('/getpeople/').succes(data) {
people = data;
// looks like this: [{'fullname': 'bill gates', 'hobby': {'hobby_name': 'programming', 'category': 'computers'}, ...]
};
</script>

ng-model needs to be set to the exact same object as the one in the ng-options array that you want to be selected. Angular uses object references to figure out which one should be active so having a "hobby-object" with the same "hobby_name" as one of the objects in "hobbies" is not enough. It needs to be a reference to the same object.
See documentation for select for details

Related

Unable to render the values in drop down list

I have a JSON text and three dropdown lists.
First dropdown list will be populating Entities (Applicant, Person, Plan).
Second dropdown list will be populating Association Types of selected Entity from previous selection.
(Here ‘Person’ and ‘Plan’ will be rendered by selecting “Applicant” as Entity)
The third dropdown list should populate the Attribute values. (Based on selection of Association Type from the second dropdown list, it should display the attributes of respective Entity)
Example: If I select Person Association type in 2nd dropdown list then Attributes of Person Entity has to be displayed.
I have tried solving this problem.
I could get the values for the first two dropdown lists. I have tried rendering the values however I am facing some problems.
Can someone help me how to get the values??
http://jsbin.com/toqisibumo/edit?html,js,output
If you dont understand question, Please dont hesitate to ask. Thanks
Hope this solve your issue.
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
</head>
<body ng-app="myApp" ng-controller="myCtrl">
<select ng-model="dd1" ng-options="item.Entity for item in data">
</select>
<select ng-model="dd2" ng-options="ass.associationType for ass in dd1.Associations" ng-change="loadDD3()">
</select>
<select ng-model="dd3" ng-options="atr.name for atr in dataDD3">
</select>
</body>
<script>
var angular = angular.module('myApp', []);
angular.controller('myCtrl', function($scope,$http) {
$scope.data = [
{
"Attributes":[
{"name":"CSRPercent","attributeType":"decimal"},
{"name":"date","attributeType":"date"},
{"name":"hoursPerWeek","attributeType":"long"},
{"name":"householdSize","attributeType":"long"},
{"name":"income","attributeType":"decimal"},
{"name":"incomePeriod","attributeType":"string"},
{"name":"isEligibleForCostSharingReduction","attributeType":"boolean"},
{"name":"isEligibleForIncomeBasedMedi_CAL","attributeType":"boolean"},
{"name":"isEligibleForMedi_Cal_Access","attributeType":"boolean"},
{"name":"isEligibleForPremiumAssistance","attributeType":"boolean"},
{"name":"state","attributeType":"string"},
{"name":"zip","attributeType":"string"}
],
"Associations":[
{"associationType":"Person","name":"familyMembers"},
{"associationType":"Plan","name":"plans"}
],
"Entity":"Applicant"
},
{
"Attributes":[
{"name":"age","attributeType":"long"},
{"name":"isPregnant","attributeType":"boolean"}
],
"Entity":"Person"
},
{
"Attributes":[
{"name":"company","attributeType":"string"},
{"name":"costPerPerson","attributeType":"decimal"},
{"name":"name","attributeType":"string"},
{"name":"premiumAssistance","attributeType":"decimal"},
{"name":"stars","attributeType":"long"},
{"name":"totalMonthlyPremium","attributeType":"decimal"},
{"name":"yourMonthlyPremium","attributeType":"decimal"}
],
"Entity":"Plan"
}
];
$scope.dataDD2 = [];
$scope.loadDD3=function(){
for(var i = 0; i < $scope.data.length; i++) {
var obj = $scope.data[i];
if(obj.Entity == $scope.dd2.associationType)
{
$scope.dataDD3 = obj.Attributes;
}
}
};
});
</script>
</html>
But still I have some issues.
For the dropdown1 you have three values(Applicant, Person, Plan).
If you select Applicant you will load Associations(Person, Plan) to the dropdown2.
What if you select either Person or Plan in dropdown1 ?
For those two you don't have associations ryt.
First of all, we can't test your jsbin, because the get request fails (ERR_NAME_NOT_RESOLVED)
Secondly, I see this line of code:
<select ng-model="z" ng-change="addAttributes()" ng-options="sel.name for sel in z.Attributes">
You've set the ng-model to 'z', and then try to get the options from 'z.Attribute', but your 'z' model is not populated with anything. Maybe you wanted to make y.Attributes ?
UPDATE:
I think you are having troubles with your JSON data.
here's an updated link.
Select Applicant -> Person -> FamilyMembers
is this the behaviour you want?
If so, look how I've modified your select:
<select ng-model="z" ng-change="addAttributes()" ng-options="color.name for color in y.names">
and this is how I've modified your JSON data:
...
"Associations":[{"associationType":"Person","names":[{"name" : "familyMembers"}]}
...
so names is an array containing your values.
I checked your codes.
In the third drop-down your loading the data from
sel.name for sel in z.Attributes
Where it has to be
sel.name for sel in x.Attributes
Then you will get the dropdown

Angular model and select not working

I've been having an issue for a day or two trying to get a select element working with my angular model.
I have a driving log, and one of the fields is truck. The value should be the truck id, which is received and sent from/to an API.
I've tried a couple methods, using ng-repeat to generate options, as well as using ng-options. The problem I ran into with the ng-repeat method was that I wasn't able to set the selected item, even with a lot of tinkering and doing things that shouldn't have to be done, and bad practice.
The second method I believe is the correct one, and it's using ng-options.
<select ng-model="timeLog.truck" convert-to-number
ng-options="truck.description for truck in trucks track by truck.id">
<option value="">Choose Truck</option>
</select>
.controller('EditTimeLogCtrl', function($scope, $stateParams, $location, timeLog, LogEntry, localStorageService) {
// edit an individual time log
$scope.timeLog = timeLog;
$scope.trucks = localStorageService.get('trucks');
$scope.saveTimeLog = function() {
LogEntry.update($scope.timeLog, function(data) {
$location.path('/tab/logs/edit');
});
}
})
Everything else in my timeLog model works, and the value in the model is an integer.
For some reason, I can't get the initial value to set correctly even though the docs specify to use this to set a default value.
The other issue I have when using ng-options is that when I submit the form, it uses the truck object {"description": "big red", "id": 7, ... } instead of the value of the option, which would just be 7. The API is expecting the id, so that does not work.
I've found 3 stackoverflow articles about that, and they all give various answers which don't really solve the problem.
This seems like a very common use case, maybe I'm thinking about it the wrong way? I just have a model which has a dropdown/select field and I need that to populate to what the selected value is if the model already exists (i.e. edit form), and pass the id value in the model save.
Your ngOptions syntax is a bit off - it's value as text for obj in arr - so change yours to:
ng-options="truck.id as truck.description for truck in trucks track by truck.id"
And then set your model to the id of the object you want selected:
$scope.timeLog.truck = 7; //truck id 7 selected.
If you want the whole object as the value:
ng-options="truck as truck.description for truck in trucks track by truck.id"
And set the whole object:
$scope.timeLog.truck = $scope.trucks[0];
Make sure your timeLog.truck IS (===) the actual object in the trucks array (same referenced object)
angular
.module('app', [])
.controller('myController', myController);
function myController($scope) {
$scope.trucks = [{
"description": "big red",
"id": 7
}, {
"description": "big yellow",
"id": 6
}];
$scope.timeLog = {truck: $scope.trucks[0]};
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.js"></script>
<div ng-app="app">
<div ng-controller="myController">
<select ng-model="timeLog.truck" ng-options="truck.description for truck in trucks">
<option value="">Choose Truck</option>
</select>
</div>
</div>

Update ngmodel from Select

We're attempting to display a customer's information based upon the contact they select. When we use ng-options it works as expected. We are, however, using Ui.Select2 and "ui-select2 is incompatible with ." So we are forced to use ng-repeat and it isn't working as expected.
JS:
var app = angular.module('App', []);
app.controller('Ctrl', function($scope){
$scope.contacts =
[ {
'CntctKey': '331518',
'Name': 'Cheryl',
'Phone': '55555115',
'PrimaryCntct': '0'
} ,
{
'CntctKey': '118431',
'EmailAddr': 'pizzamaybe#gmail.com',
'Name': "Stephanie Pizza",
'Phone': '555552255',
'PrimaryCntct': '1'
} ];
});
HTML
<h3>With ng-options</h3>
<select ng-model="contactedPerson" ng-options="contact.Name for contact in contacts"></select>
<input ng-model="contactedPerson.Phone"/>
<input ng-model="contactedPerson.CntctKey"/>
<br>
<h3>With ng-repeat</h3>
<select ng-model="contactPerson1" >
<option ng-repeat="contact in contacts" value="{{contact}}">{{contact.Name}}</option>
</select>
<input ng-model="contactPerson1"/>
<input ng-model="contactPerson1.Cntctkey"/>
http://plnkr.co/edit/9D9LTCnBOGAo2ftA1jbU
You can see that with ng-repeat it shows the object but we can't drill it into it any further.
Is there a good way to do this besides using ng-options? Thanks in advance!
The problem is that you are using value="{{contact}}"
This causes angular to print the object as a JSON string.
So when the value gets assigned from the ng-model in the select list, the variable is assigned a string value i.e.
"{"CntctKey":"331518","Name":"Cheryl","Phone":"55555115","PrimaryCntct":"0"}", rather than the object's itself.
This is why in your plnkr, your second field which has ng-model="contactPerson1.CntctKey" has no value, because for a string, this property is undefined.
to fix this you can just use the index of the array element to reference the object.
You can access this index by using ng-repeat's key mapping (contactKey, contact) in contacts.
Or if you are just storing everything in a flat, contiguous array (like in the example), just use ng-repeat's $index variable.
i.e.
<select ng-model="contactPerson1Index" >
<option ng-repeat="contact in contacts" value="{{$index}}">{{contact.Name}}</option>
</select>
<input ng-model="contacts[contactPerson1Index].Phone"/>
<input ng-model="contacts[contactPerson1Index].CntctKey"/>
See updated plnkr: http://plnkr.co/edit/4thQmsZamN3tt0xpscj9
for more info on key mapping and ng-repeats internal variables, see: https://docs.angularjs.org/api/ng/directive/ngRepeat

How to trigger binding of select based on the changed value in another select?

Let's say that I have list of countries and each country has a list of states/regions. So there are two selects. First to select country, and when country changes I want to trigger binding of the states select. How do you link these two controls to trigger binding of the states select when country changes?
<select id="countries"
data-ng-model="vm.permanentAddress.countryCode"
data-ng-options="country.code for country in vm.form.countries">
</select>
<select data-ng-model="vm.permanentAddress.stateCode"
data-ng-options="state.value for state in vm.getStatesForCountry(vm.permamentAddress.countryCode)">
</select>
UPDATE:
I was probably not explicit in my question as to what I want to do. I do not want to create any new properties that are then watched by angular for a change. I just want to tell anuglar, hey something has changed, go ahead and re-evaluate the binding for this control.
Is it not possible?
In your controller have something like this:
$scope.setStateOptions = function(country){
$scope.stateOptions = /* whatever code you use to get the states */
}
Then your html can be:
<select id="countries"
data-ng-model="vm.permanentAddress.countryCode"
data-ng-options="country.code for country in vm.form.countries"
data-ng-change="setStateOptions(country)">
</select>
<select
data-ng-model="vm.permanentAddress.stateCode"
data-ng-options="state.value for state in stateOptions">
</select>
May be you should use the jquery chanied select plugin:
http://jquery-plugins.net/chained-selects-jquery-plugin
I have used it for 4 select list chained and it worked fine.
Thx
Here is a working example. You just need to use the ng-change to change the model you have set for the states
You can take advantage of the dynamic nature of JavaScript to bind the key from the first list to the second list. Then you only have to set a default value on the change. If you remove the $watch it will still work, the second select will just default to empty when you switch the category.
Here's my data set-up and watch:
app.controller("myController", ['$scope', function($scope) {
$scope.data = ['shapes', 'colors', 'sizes'];
$scope.data.shapes = ['square', 'circle', 'ellipse'];
$scope.data.colors = ['red', 'green', 'blue'];
$scope.data.sizes = ['small', 'medium', 'large'];
$scope.category = 'colors';
$scope.$watch('category', function () {
$scope.item = $scope.data[$scope.category][0];
});
And here's the HTML:
<div ng-app="myApp" ng-controller="myController">
<select id="categories"
data-ng-model="category"
data-ng-options="category for category in data"></select>
<select id="item"
data-ng-model="item"
data-ng-options="item for item in data[category]"></select>
{{category}}: {{item}}</div>
You can, of course, change this to host complex objects and use keys or other identifiers to switch between the lists. The full fiddle is here: http://jsfiddle.net/jeremylikness/8QDNv/

Modifying an array within an object that's displayed in a ng-repeat

I'm trying to update a $scope object's array that is displayed in a ng-repeat on the page using input elements containing the array's contents. The plunker example can be found here: Plunker demo (Basic, stripped down example of my problem)
I have the following settings object defined:
$scope.settings = {
list: ['list item one', 'list item two', 'list item three']
};
and I am representing the data on the page like so:
<ul>
<li ng-repeat="item in settings.list">
<input type="text"
value="{{item}}"
ng-model="singleItem"
ng-change="settings.list[$index] = singleItem" />
delete
</li>
</ul>
My goal is to initially populate the <input> fields with the contents of $scope.settings.list and whenever an item is changed update the array, but I haven't figured out how to in the view. Omitting the ng-model and ng-change on the input properly renders the input vale in the text boxes, but then the array isn't modified when changes are made.
Side Note:
In the Plunker example I have $watch on the settings object. In my actual code, this is used to update a "settings cookie" using the $cookies module. Cookies have been omitted in the example, but for debugging purposes I have left the watch in.
There are two primary problems with your approach. The first is that ngRepeat uses an inherited scope, so primitive values (like strings and numbers) don't play nicely. You should pass arrays of objects to ngRepeat rather than arrays of primitives. Your second problem is the over-complicated way of of binding to an input. All you need is to this:
$scope.settings = {
list: [
{ val: 'list item one'},
{ val: 'list item two'},
{ val: 'list item three'}
]
};
And then in your view:
<ul>
<li ng-repeat="item in settings.list">
<input type="text" ng-model="item.val"></input>
<a ng-click="remove($index)">delete</a>
</li>
</ul>
Here's a revised plunker: http://plnkr.co/edit/ZGFjBnVSwM4hNSgVSOCW?p=preview .

Resources