Select, with ng-repeat, current value of ng-model doesn't appear - javascript

I have this code above:
<select ng-model = "vm.modulo.nomenclatura" class="form-control" required>
<option></option>
<option ng-value="modulo.key" ng-repeat="modulo in vm.availableModulos">{{modulo.value}}</option>
</select>
The thing is, the ng-model current value (even before been selected an option), does not shows up on the field. It's blank. Could somebody help?
Thank you

You should be using ng-options instead of repeating the options
Check this fiddle out - https://plnkr.co/edit/XpgXNOPjC9ZJ8lYuPhGP?p=preview
angular.module("sampleApp", [])
.controller("sampleController", function() {
var vm = this;
vm.availableModulos = [
{value: "Value 1"}
{value: "Value 2"},
{value: "Value 3"},
{value: "Value 4"},
{value: "Value 5"}
];
vm.modulo = {nomenclatura: vm.availableModulos[2]};
});
<body data-ng-controller="sampleController as vm">
{{vm.modulo.nomenclatura}}
<select ng-model = "vm.modulo.nomenclatura" class="form-control" required ng-options="mod as mod.value for mod in vm.availableModulos">
<option></option>
</select>
</body>

The best practice in using angular select tag is using ng-options rather than using ng-repeat inside options. Use angular ng-options and track by expression to track your model value. There should be a unique id field that should be provided as track by key. Th ng-model will be initialized on the basis of the track by value.
Here is a working demo.
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
</head>
<body>
<div ng-app="myApp" ng-controller="myCtrl as vm">
<select ng-model="vm.modulo.nomenclatura" class="form-control" required ng-options="option.value for option in vm.availableModulos track by option.id"> </select>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function ($scope, $timeout) {
var _self = this;
_self.availableModulos = [ { value: "Value 1", id: 0 },
{ value: "Value 2", id: 1 },
{ value: "Value 3", id: 2 },
{ value: "Value 4", id: 3 },
{ value: "Value 5", id: 4 }
];
_self.modulo = {
nomenclatura: _self.availableModulos[2]
};
});
</script>
</body>
</html>

Related

AngularJS Ng-model-options not able to select object in getter-setter function

I have a problem selecting an object from ng-model with ng-model-options and getter-setter function. I am binding to the ng-model getter-setter function setGetSelectedItem which has to accept an object from ng-options - in my case, item and to assign its properies to the properties of another object specific_data. It does, the object is passed correctly but I am not able to select the option in the select options.
<select name="item" ng-model="setGetSelectedItem"
ng-options="item as item.title for item in items"
ng-model-options="{getterSetter: true}">
<option value="">-- Please select --</option>
</select>
And in the controller:
$scope.items = [{
"description": "Item description",
"item_type": "OUT",
"id": 1,
"title": "Default item"
}];
$scope._objectDataRaw = {
specific_data: {}
};
$scope.setGetSelectedItem = function(value) {
if (arguments.length) {
$scope._objectDataRaw.specific_data.property_id = value.id;
$scope._objectDataRaw.specific_data.property_title = value.title;
$scope._objectDataRaw.specific_data.property_description =
value.description;
return $scope._objectDataRaw.specific_data;
}
};
Here is a jsfiddle with the problem:
Can not select the object
And I need it to pass it as an object, and not as object.property.
Any help would be greatly appreciated.
Instead of using the getterSetter option, use the ng-change directive to set the specific_data object:
<select name="item" ng-model="selectedItem"
ng-options="item as item.title for item in items"
̶n̶g̶-̶m̶o̶d̶e̶l̶-̶o̶p̶t̶i̶o̶n̶s̶=̶"̶{̶g̶e̶t̶t̶e̶r̶S̶e̶t̶t̶e̶r̶:̶ ̶t̶r̶u̶e̶}̶"̶
ng-change="setSelectedItem(selectedItem)" >
<option value="">-- Please select --</option>
</select>
The DEMO
angular.module("app",[])
.controller("ctrl", function($scope) {
$scope.items = [{
"description": "Item description",
"item_type": "OUT",
"id": 1,
"title": "Default item"
}];
$scope._objectDataRaw = {
specific_data: {}
};
$scope.setSelectedItem = function(value) {
$scope._objectDataRaw.specific_data.property_id = value.id;
$scope._objectDataRaw.specific_data.property_title = value.title;
$scope._objectDataRaw.specific_data.property_description =
value.description;
};
})
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="app" ng-controller="ctrl">
<select name="item" ng-model="selectedItem"
ng-options="item as item.title for item in items"
ng-change="setSelectedItem(selectedItem)" >
<option value="">-- Please select --</option>
</select>
<hr>
_objectDataRaw={{_objectDataRaw}}
</body>
I think your code should be:
angular.module('myApp', [])
.controller('Ctrl1', function($scope) {
$scope.items = [{
"description": "Item description",
"item_type": "OUT",
"id": 1,
"title": "Default item"
}];
$scope._objectDataRaw = {
specific_data: {}
};
$scope.setGetSelectedItem = function(value) {
if (arguments.length) {
$scope._objectDataRaw.specific_data.property_id = value.id;
$scope._objectDataRaw.specific_data.property_title = value.title;
$scope._objectDataRaw.specific_data.property_description = value.description;
return $scope._objectDataRaw.specific_data;
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="Ctrl1">
<div>
<select name="item" ng-repeat="item in items">
<option value="">-- Please select --</option>
<option value="" ng-click="setGetSelectedItem(item)">{{item.title}}</option>
</select>
</div>
</div>

trying to set data and selected option to select in angular js

In my application i have select that i bind with options and the user selected saved data on page load.
Fiddle Link for issue
<div ng-app ng-controller="QuestionController">
<ul ng-repeat="question in Questions">
<li>
<div>{{question.Text}}</div>
<select ng-model="Answers['{{question.Name}}']" ng-options="option for option in question.Options">
</select>
<select ng-model="OptSelected" ng-options="option for option in question.Options">
</li>
</ul>
</div>
And in my angular controller
function QuestionController($scope) {
$scope.Answers = {};
$scope.Questions = [{ "Text": "Gender?", "Name": "GenderQuestion",
"Options": [{1,"Male"}, {2,"Female"}],
"OptSelected": [{1,"Male"}]},{ "Text": "Favorite color?","Name": "ColorQuestion",
"Options": [{1,"Red"}, {2, "Blue"}, { 3,"Green"}],"OptSelected": [{ 2, "Blue"}] }];
angular.forEach($scope.Questions, function(q) {
var propModel = "Answers['" + q.Name + "']";
$scope[propModel] = q.OptSelected;
})
In my application I am successful at binding data to select but i canot set the user saved value to select.
I have tried to recreate the issue with fiddle without much success but I think it will provide you all better understanding of what I am trying to do
I would recommend binding to just the Questions array and avoid the complexity of trying to bind to the corresponding question in an Answers array. You can always extract what you need from the Questions array either after a selection has been made or all together through some controller level action.
That said, part of your problem is that you don't have a well formed array of objects.
Here's a simplified, working version:
var app = angular.module('myApp', []);
app.controller('QuestionController', function($scope) {
$scope.Questions = [{
Text: "Gender?",
Name: "GenderQuestion",
Options: [{
id: 1,
desc: "Male"
}, {
id: 2,
desc: "Female"
}],
OptSelected: {
id: 1,
desc: "Male"
}
}, {
Text: "Favorite color?",
Name: "ColorQuestion",
Options: [{
id: 1,
desc: "Red"
}, {
id: 2,
desc: "Blue"
}, {
id: 3,
desc: "Green"
}],
OptSelected: {
id: 2,
desc: "Blue"
}
}];
});
<html ng-app="myApp">
<head>
<meta charset="utf-8" />
<script>
document.write('<base href="' + document.location + '" />');
</script>
<script data-require="angular.js#1.5.x" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.11/angular.min.js" data-semver="1.5.11"></script>
</head>
<div ng-controller="QuestionController">
<ul ng-repeat="question in Questions">
<li>
<div>{{question.Text}}</div>
<select ng-model="question.OptSelected" ng-options="option as option.desc for option in question.Options track by option.id">
</select>
</li>
</ul>
</div>
</html>

Dropdown binding issue with track by

I am getting problem while binding my dropdown value with associative array.
Problem is with track by so like when I don't add track by to my dropdown then I have my binding with dropdown and when I add track by then O am unable to auto select dropdown value.
I want to use track by with ng-options so that angular js doesn't add
$$hashKey and leverage performance benefit associated with track by.
I am not getting why this behaviour is happening.
Note: I only want to bind name of choices like Pizza or burger for each of my $scope.items and not whole object.
Update: As I understand and with so much trying with current data structure of my $scope.items it is not working with ng-options and I want to use ng-options with track by to avoid generating hash key by Angular js. I also tried ng-change as suggested by #MarcinMalinowski but I am getting key as undefined.
So what should be my data structure of $scope.items so that when I need to access any item from my $scope.items? I can access it without doing loop (like we access items from associative array) like how I can access now with correct data structure and using ngoptions only with track by.
var app = angular.module("myApp", []);
app.controller("MyController", function($scope) {
$scope.items = [
{
"title": "1",
"myChoice" :"",
"choices": {
"pizza": {
"type": 1,
"arg": "abc",
"$$hashKey": "object:417"
},
"burger": {
"type": 1,
"arg": "pqr",
"$$hashKey": "object:418"
}
}
},
{
"title": "2",
"myChoice" :"",
"choices": {
"pizza": {
"type": 1,
"arg": "abc",
"$$hashKey": "object:417"
},
"burger": {
"type": 1,
"arg": "pqr",
"$$hashKey": "object:418"
}
}
}
];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<ul ng-app="myApp" ng-controller="MyController">
<div ng-repeat="data in items">
<div>{{data.title}}
</div>
<select ng-model="data.myChoice"
ng-options="key as key for (key , value) in data.choices track by $index"><option value="">Select Connection</option></select>
</div>
</ul>
The problems in your code are:
1) track by $index is not supported by ngOptions, it will result the value of the option to be undefined(in your case it will be an $index of ngRepeat);
2) track by doesn't work well with object data-sources (it is supposed to be used with array data-sources), from the docs:
trackexpr: Used when working with an array of objects. The result of
this expression will be used to identify the objects in the array.
Of course, you can use ngRepeat to generate option elements, but personally, I would prefer using ngOptions without track by due to the benefits it has over ngRepeat.
UPDATE: Here is the code that illustrates how you can change your initial data-source and use track by to pre-select an option in case the model is an object. But even in the first example console.log() shows that $$hashKey was not added to choices object.
var app = angular.module("myApp", []);
app.controller("MyController", ['$scope', '$timeout', function($scope, $timeout) {
$scope.items = [
{
"title": "1",
"myChoice" :"burger",
"choices": {
"pizza": {
"type": 1,
"arg": "abc"
},
"burger": {
"type": 1,
"arg": "pqr"
}
}
},
{
"title": "2",
"myChoice" :"",
"choices": {
"pizza": {
"type": 1,
"arg": "abc"
},
"burger": {
"type": 1,
"arg": "pqr"
}
}
}
];
$scope.itemsTransformed = angular.copy($scope.items).map(function(item){
delete item.myChoice;
item.choices = Object.keys(item.choices).map(function(choice){
item.choices[choice].name = choice;
return item.choices[choice];
});
return item;
});
//select an option like an object, not a string
$scope.itemsTransformed[1].myChoice = $scope.itemsTransformed[1].choices[0];
$timeout(function() {
//changes a prop in opts array - options are not-re-rendered in the DOM
//the same option is still selected
$scope.itemsTransformed[1].choices[0].arg = "xyz";
}, 3000);
$scope.selectionChanged =function(key, items){
console.log(items); //as we can see $$hashKey wasn't added to choices props
};
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<ul ng-app="myApp" ng-controller="MyController">
<p>Without track by:</p>
<div ng-repeat="data in items track by data.title">
<div>{{data.title}} - {{data.myChoice}}</div>
<select ng-model="data.myChoice"
ng-options="key as key for (key , value) in data.choices"
ng-change="selectionChanged(key, items)">
<option value="">Select Connection</option>
</select>
</div>
<hr/>
<p>Using track by name to pre-select an option:</p>
<div ng-repeat="data in itemsTransformed track by data.title">
<div>{{data.title}} - {{data.myChoice}}</div>
<select ng-model="data.myChoice"
ng-options="choice as choice.name for choice in data.choices track by choice.name"
ng-change="selectionChanged(key, itemsTransformed)">
<option value="">Select Connection</option>
</select>
</div>
</ul>
UPDATE 2: A simple example that shows us the fact $$hashKey property is not added to the objects when using ngOptions without track by:
var app = angular.module("myApp", []);
app.controller("MyController", ['$scope', '$timeout', function ($scope, $timeout) {
$scope.items = {
"pizza": {
"type": 1,
"arg": "abc"
},
"burger": {
"type": 1,
"arg": "pqr"
}
};
$scope.selectionChanged = function (key, items) {
console.log($scope.items);
};
}]);
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyController">
<hr/>
<p>Example without track by:</p>
<select ng-model="myChoice"
ng-options="key as key for (key , value) in items"
ng-change="selectionChanged(myChoice, items)">
<option value="">Select Connection</option>
</select>
<hr/>
{{myChoice}}
</div>
UPDATE 3: Final result below (that work with angularjs versions < 1.4, for 1.4+ I would recommend changing the data structure as $scope.itemsTransformed in the first code snippet):
angular.module("myApp", [])
.controller("MyController", ['$scope', function ($scope) {
$scope.items = [
{
"title": "1",
"myChoice": "burger",
"choices": {
"pizza": {
"type": 1,
"arg": "abc"
},
"burger": {
"type": 1,
"arg": "pqr"
}
}
},
{
"title": "2",
"myChoice": "",
"choices": {
"pizza": {
"type": 1,
"arg": "abc"
},
"burger": {
"type": 1,
"arg": "pqr"
}
}
}
];
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyController">
<div ng-repeat="data in items track by data.title">
<div>{{data.title}} {{data.myChoice}}</div>
<select ng-model="data.myChoice"
ng-options="key as key for (key , value) in data.choices">
<option value="">Select Connection</option>
</select>
</div>
</div>
ngOptions doesn't create new scope like ngRepeat directive per item therefore you don't need to take care about to get rid of $$hashKey
I would use ng-repeat to iterate on <option> (suppose you don't create long lists):
<select ng-model="data.myChoice">
<option value="">Select Connection</option>
<option ng-repeat="(key , value) in data.choices track by key" ng-value="key" title="{{key}}"
>{{key}}</option>
</select>
Working Demo Fiddle
Take look on this issue: github.com/angular/angular.js/issues/6564 - ng-options track by and select as are not compatible
I believe this issue still exists so suggest you to use ngRepeat with track by instead. For small list there is no performance penalty
ngOptions attribute can be used to dynamically generate a list of elements for the element using the array or object
ngModel watches the model by reference, not value. This is important to know when binding the select to a model that is an object or a collection.
1.If you set the model to an object that is equal to an object in your collection, ngOptions won't be able to set the selection, because the objects are not identical. So by default, you should always reference the item in your collection for preselections, e.g.: $scope.selected = $scope.collection[3]
ngOptions will track the identity of the item not by reference, but by the result of the track by expression. For example, if your collection items have an id property, you would track by item.id.
For Example :
$scope.items = [
{
"title": "1",
"myChoice" :"",
"choices": {
"pizza": {
"type": 1,
"arg": "abc"
},
"burger": {
"type": 1,
"arg": "pqr"
}
}
},
{
"title": "2",
"myChoice" :"",
"choices": {
"pizza": {
"type": 1,
"arg": "abc"
},
"burger": {
"type": 1,
"arg": "pqr"
}
}
}
];
From the above 2nd point, track the identity of the item not by reference.
Add keyName of key in the object and track by keyName or track by arg , type.
Track by arg or type :
<select ng-model="data.myChoice"
ng-options="choice as choice.arg for choice in data.choices track by choice.arg">
<option value="">Select Connection</option>
</select>
Or add keyName inside the choice object
$scope.items = $scope.items.filter(function(item){
delete item.myChoice;
item.choices = Object.keys(item.choices).map(function(choice){
item.choices[choice].keyName = choice;
return item.choices[choice];
});
return item;
});
HTML Code:
<div ng-controller="MyCtrl">
<ul>
<div ng-repeat="data in items">
<select ng-model="data.selected"
ng-options="choice as choice.keyName for choice in data.choices track by choice.keyName"
ng-change="selection(data.selected)">
<option value="">Select</option>
</select>
</div>
</ul>
</div>
Demo Link Example
You need to add ng-change and pass/use your ng-model value there to get any property you wish.
<select class="form-control pickupaddress ng-pristine ng-valid ng-touched m-r-sm m-t-n-xs" ng-model="item.pickup_address" tabindex="0" aria-invalid="false" ng-options="add._id as add.nick_name for add in addPerFood[item.food._id] | unique:'nick_name'" ng-change="dropDownSelect(item.pickup_address,allCarts,item,$index)">

How to select default drop-down option in select list in Angular JS

I have the following select option :
<select ng-model="class_name" name="class_name" class="form-control">
<option ng-repeat="t in MemberClass" value="{{t}}">{{t.class_name}}</option>
</select>
I want to set default option MemberClass[0] to select option. I tried the following code but not working.
The JSON data is coming from Webservice...
//To fetch Member Class
$http.get('http://192.168.1.6:8080/apartment//member/class/list').then(function(response) {
$scope.MemberClass = response.data.list;
$scope.class_name = $scope.MemberClass[0]; // Not working
});
Member class JSON data is :
[
{
"class_id": 1,
"class_name": "Owner",
"class_details": "DCE"
},
{
"class_id": 7,
"class_name": "Staff "
},
{
"class_id": 10
"class_name": "Vendor"
}
]
Plunker sample : https://plnkr.co/edit/vVcrmOREkcVBBM2Ynhgv?p=preview
(Am getting error if I not select any option...)
You can utilize ng-options for this. It is the preferred way most of the times. Like this:
<select ng-model="class_name" ng-options="t as t.class_name for t in MemberClass">
</select>
Now, since you have $scope.class_name assigned as default value, it will be selected already.
working example
Use ng-init. Try like below.
<!DOCTYPE html>
<html ng-app="myApp" ng-controller="Ctrl">
<body>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<div class="form-group">
<label class="control-label col-md-3">Member Class </label>
<div class="col-md-4">
<select ng-model="class_name"
ng-init=" class_name = MemberClass[0]" name="class_name" ng-options="t as t.sub_class_name for t in MemberClass">
</select>
<p>Selected Value: {{class_name}} <p>
</div>
</div>
<button type="submit" ng-click="alertdata()">Save</button>
<script>
angular.module('myApp', [])
.controller('Ctrl', function($scope) {
var MemberClass;
$scope.MemberClass = [{
"sub_class_id": 1,
"sub_class_name": "Primary"
},
{
"sub_class_id": 2,
"sub_class_name": "Secondary "
},
{
"sub_class_id": 3,
"sub_class_name": "Dependent "
},
{
"sub_class_id": 4,
"sub_class_name": "Sub Member"
},
{
"sub_class_id": 5,
"sub_class_name": "None"
}
]
// $scope.class_name = $scope.MemberClass[0];
$scope.alertdata = function() {
$scope.class_name = "{}";
var parameter;
parameter = {
"member": {
"first_name": "first_name",
"role": [{
"role_id": 4
}],
"associated": "associated",
"class0": [JSON.parse($scope.class_name)],
"contect": [{
"intercom": "intercom"
}],
"individualdetails": [{
"gender": "gender"
}]
},
"address": [{
"street_address_1": "street_address_1"
}]
}
console.log(JSON.stringify(parameter));
};
});
</script>
</body>
</html>
You should definitly use ng-options for this
<select ng-model="class_name" ng-options="t as t.class_name for t in MemberClass">
</select>
To set a default, either set the $scope.class_name to a value of the MemberClass array or you can add an empty option tag as below which will be selected when the $scope.class_name is null
<select ng-model="class_name" ng-options="t as t.class_name for t in MemberClass">
<option value="">Select value</option>
</select>

ng-select dropdown ajax/object mapping

Using angular ng-select, looking for the best practice/suggestion for linking the select drop-down with the selected option selected based on the properties of an object in scope.
The controller holds an object that (animal) that has a selected cat
The cats (options) are loaded from an Ajax call using any "promise" type angular service ($http in demo)
When the page loads, I want the selected cat to be the same as the animal.cat (would love to see easiest path to bi-directional mapping)
Here is the plunker: http://plnkr.co/edit/bMj7678djgPoJbiTRceG?p=preview
Service/Controller JS.
selectDemo = angular.module('selectDemo',[]);
selectDemo.factory("cat", ["$http", "$log", function($http, $log){
return {
query: function(runAfter){
$log.debug("Getting cats from service");
return $http.get('getCats.json');
}
}
}]);
selectDemo.controller('SelectDemoCtrl', ["$scope", "$log", "cat", function($scope, $log, Cat){
$scope.animal = {type: "Mammal", cat: {"id": 2, "name": "Simon", "breed": "Persian"}};
Cat.query().then(function(data){
cats = data.data;
$scope.cats = cats;
});
}]);
Html:
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.js"></script>
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
</head>
<body ng-app="selectDemo" ng-controller="SelectDemoCtrl">
<h1>AngularJS Select Dropdown</h1>
<div id="data"></div>
<form role="form">
<select data-ng-model="animal.cat" data-ng-options="cat.name for cat in cats">
<option value="">Select a cat</option>
</select>
</form>
<p>You selected: {{ animal.cat }}</p>
</body>
</html>
JSON Response Object:
[{"id": 1, "name": "Garfield", "breed": "Tabby"},
{"id": 2, "name": "Simon", "breed": "Persian"},
{"id": 3, "name": "Twix", "breed": "Mixed"}]
Here's an updated plunk:
http://plnkr.co/edit/KTJt9602eD5Pgr1y7c9w?p=preview
The issue here is that the selected object from the ng-options needs to be reference equal to the object referenced by ng-model, hence the need to find the object in the array.

Categories

Resources