Object.keys() not working in ng-options - javascript

I am trying to create a dropdown list using ng-options:
<!DOCTYPE html>
<html ng-app="m1">
<head>
<script src='https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.min.js'></script>
</head>
<body ng-controller="c1">
<div>
Sort1
<select ng-model="sortKey1">
<option value="bookId">By Id</option>
<option value="bookTitle">By Title</option>
<option value="cost">By Cost</option>
</select>
</div>
<div>
Sort2
<select ng-model="sortKey2" ng-options="x for x in Object.keys(books[0])">
</select>
</div>
<div>
Sort3
<select ng-model="sortKey3" ng-options="x for x in bookKeys">
</select>
</div>
</body>
<script type="text/javascript">
var m1 = angular.module("m1", []);
m1.controller('c1',function($scope)
{
$scope.books = [
{
"bookId": 101,
"bookTitle": "Angular JS",
"cost":375,
},
{
"bookId": 102,
"bookTitle": "Instant AngularJS Starter",
"cost":150,
},
{
"bookId": 103,
"bookTitle": "Ng-Book: The Complete Book on AngularJS",
"cost":4657,
}];
console.log(Object.keys($scope.books[0]));
$scope.bookKeys = Object.keys($scope.books[0]);
});
</script>
</html>
I am trying to get the dropdown values from an object's keys by calling Object.keys() on an object and then using the resultant array in ng-options.
I am trying to create the effect of case 1. My attempt at case 2 is not working, however a similar thing implemented in case 3 is working.
Can anybody tell the reason why case 2 is not working?

Update
As indicated in Zen's answer, the reason Object.keys() does not work in ng-repeat is due to the context in which it is evaluated (that being the context of $scope).
Angular has this functionality built in in the form of (key, val). Sometimes the support for native javascript functions within an Angular express is limited and in this instance Angular probably doesn't understand Object.keys() as the source for ng-options. Change the <select> in your case 2 to:
<select ng-model="sortKey2" ng-options="key as key for (key,val) in books[0]">
Working example:
var m1 = angular.module("m1", []);
m1.controller('c1', function($scope) {
$scope.books = [{
"bookId": 101,
"bookTitle": "Angular JS",
"topic": "AngularJS",
"author": "Green",
"cost": 375,
}, {
"bookId": 102,
"bookTitle": "Instant AngularJS Starter",
"topic": "AngularJS",
"author": "Dan Menard",
"cost": 150,
}, {
"bookId": 103,
"bookTitle": "Ng-Book: The Complete Book on AngularJS",
"topic": "AngularJS",
"author": "Ari Lerner",
"cost": 4657,
}];
console.log(Object.keys($scope.books[0]));
$scope.bookKeys = Object.keys($scope.books[0]);
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.min.js"></script>
<div ng-app="m1" ng-controller="c1">
<div>
Sort1
<select ng-model="sortKey1">
<option value="bookId">By Id</option>
<option value="bookTitle">By Title</option>
<option value="topic">By Topic</option>
<option value="author">By Author</option>
<option value="cost">By Cost</option>
</select>
</div>
<div>
Sort2
<select ng-model="sortKey2" ng-options="key as key for (key,val) in books[0]">
</select>
</div>
<div>
Sort3
<select ng-model="sortKey3" ng-options="x for x in bookKeys">
</select>
</div>
</div>
EDIT: (applied to answer) If you want the value of a select option to not become the value of the object (for eg. 101, AngularJS etc.), you can write <select ng-model="sortKey2" ng-options="key as key for (key,val) in books[0]">

All binding expressions are evaluated relative to $scope. So when you write for x in Object.keys(books[0]), angular runs it as for( x in $scope.Object.keys([books[0]) ). Apparently, Object is not defined in the scope chains. If you want it to work, you can copy all global variables to the $rootScope, that doesn't seem to be a bad habit.
m1.run([`$rootScope`, function($rootScope){
var keys = Object.getOwnPropertyNames( window );
keys.forEach( key => {
$rootScope[key] = window[key];
});
}])

Related

angular js ng-option not working for select tag

I'm trying to get the ng-option to use a JSON formatted array, but not sure why it's not displaying the select option rows. For instance:
index.js:
$scope.seloptions= [{ key: k1, name: n1 },{ key: k2, name: n2 }];
index.html:
<select name="set_aside" ng-model="set_aside" ng-options="option.key for option in seloptions track by name"></select>
I have no idea what I'm doing wrong. The select tag is not getting populated.
EDIT
Also assume that the necessary setup for the angular code is there and both files are in same directory.
The problem is that you are tracking by name which is undefined.
update line :
ng-options="option.key for option in seloptions track by name"
to
ng-options="option.key for option in seloptions track by option.name"
Working example :
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.seloptions= [{ key: "key1", name: "n1" },{ key:" key2", name: "n2" }];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="plunker">
<div ng-controller="MainCtrl">
<select name="set_aside" ng-model="set_aside" ng-options="option.key for option in seloptions track by option.name">
<option value="">Select One</option>
</select>
</div>
</body>

Is it possible to pass a variable in ng-repeat?

I'm new to angular and was wondering is it possible to replace firstP inside ng-repeat Directive with a variable? I'm using AngularJS v1.6.6
ng-repeat="option in people['firstP']"
var people = {
"firstP": [
"",
"James",
"Jack",
],
"SecondP": [
"",
"Bill",
"Bob",
]
};
is it possible to replace firstP inside ng-repeat Directive with a variable?
Yes it's possible to replace firstP with a variable, after all you are just using the normal javascript object bracket notation in Angular.
Solution:
If you are trying to display the people object contents dynamically, then you can do it like this:
<div ng-repeat="(key, value) in people">
<select>
<option ng-repeat="option in people[key]">{{option}}</option>
</select>
</div>
First you need to loop over the people object keys, then for each key take the relevant array, then loop over each array to display its contents.
Note:
Note that we can replace the people[key] with value directly in the ng-repeat so it becomes ng-repeat="option in value".
I just used people[key] for the question purpose, to answer your specific question.
Demo:
Here's a live working Plunker.
I think you have to assign people object to $scope variable in order to access people object in your html.
HTML
<html ng-app="myApp" ng-controller="testCtrl">
<ul>
<li ng-repeat="name in people[element]">{{name}}</li>
</ul>
</html>
JS
var app = angular.module('myApp', []);
var testCtrl = function($scope){
$scope.element = 'firstP';
$scope.people = {
"firstP" : [
"Jake",
"James",
"Jack",
],
"SecondP" : [
"",
"Bill",
"Bob",
]};
}
app.controller('testCtrl',['$scope',testCtrl]);
to check https://jsfiddle.net/0zk4mfak/6/
As per my understanding,
Define the array in your controller with the $scope variable:
In controller:
app.controller('nameCtrl', function($scope) {
$scope.people = { firstP: ['james', 'jack'] };
});
In Html:
<div ng-controller="nameCtrl">
<ul>
<li ng-repeat="option in people.firstP">{{option}}</li>
</ul>
</div>
Try this.Hope it helps..!
Your code looks suspiciously like it will populate a select (dropdown) box. If that is the case use ng-options for Angular 1:
Given this array of items on the $scope:
$scope.items = [{
id: 1,
label: 'aLabel',
subItem: { name: 'aSubItem' }
}, {
id: 2,
label: 'bLabel',
subItem: { name: 'bSubItem' }
}];
This will work:
<select ng-options="item as item.label for item in items track by item.id"
ng-model="selected"></select>
$scope.selected = $scope.items[0];
or ngFor in Angular 2 like in this answer:
<select name="selectmake" [(ngModel)]="makeListFilter">
<option *ngFor="let muscleCar of muscleCars" [ngValue]="muscleCar">
{{muscleCar.name}}
</option>
</select>

Bind from ngstorage to dropdown

I used ngstorage to save some value in localstorage
My contrroller is:
app.controller("main", function( $scope, $localStorage) {
$scope.$storage = $localStorage.$default({
selectedlanguage: { language: null, text: "All Languages" }
});
$scope.languages = [
{ language: null, text: "All Languages" },
{ language: "en", text: "English" },
{ language: "ar", text: "Arabic" }
];
}
My view is:
<select ng-model="$storage.selectedlanguage" ng-options="lang.text for lang in languages">
</select>
when reload the page angular can not bind the selectedlanguage
Thanks in advance
In the ng-options attribute, you can specify the values and title for each option in the expression it self, your other issue was that you're specifying an object as the ng-model, you need to tell the dropdown which value to match on, so accessing language on the selectedlanguage object will work fine.
<select ng-model="$storage.selectedlanguage.language" ng-options="lang.language as lang.text for lang in languages">
</select>
The above is the same as below, but a more complex expression, the below is just easier to read but it's exactly the same:
<select ng-model="$storage.selectedlanguage.language">
<option ng-repeat="lang in languages" value="{{lang.language}}">
{{lang.text}}
</option>
</select>
Demo: https://jsfiddle.net/suunyz3e/289/

Use select in angular to pass multiple arguments

In Angular Js is there a way to use a select element the same way you can with a list of links?
For example if I have some links like this:
<a ng-click="ctrl.change('argument1','argument2')">One</a>
<a ng-click="ctrl.change('argument3','argument4')">Two</a>
...
Is there a way I can do the same thing with a select element?
<select>
<option value="argument1,argument2">One</option>
<option value="argument3,argument4">Two</option>
...
</select>
you can pass the variables and model through ng-change , hope below code helps you,
template
<div ng-controller="myCtrl">
<select ng-model="item" ng-options="i.name for i in items" ng-change="changed('hello','world',item)">
<option value="">choose items</option>
</select>
</div>
controller
function myCtrl($scope) {
$scope.items = [{
"name": "first",
"type" : "type1"
}, {
"name": "second",
"type" : "type2"
}, {
"name": "third",
"type" : "type3"
}];
$scope.changed = function (hello,world,item) {
alert(hello); // argument1
alert(world); //argument2
alert(item.type); //model argument based on the selection
}
}
do u mean this? use controller value instead of scope value if u wish
<select ng-options="['a,b','c,d']" ng-model="selected" ng-change="ctrl.change(selected)">

using ng-options with angular to display select option with key and value and setting a default value

I have the following json:
[
{"country": "United States", "code": "US"},
{"country": "Canada", "code": "CA"},
{"country": "Mexico", "code": "MX"}
]
In my view i have
<select ng-model="selectedCountry" name="selectedCountry" id="selectedCountry" ng-options="country.country as country.country for country in countries" ng-change="onCountryChange()" required></select>
i am able to set a default country in my controller but the only problem is the drop down looks like this
<option value="0" selected="selected">United States</option>
<option value="1">Canada</option>
<option value="2">Mexico</option>
when i add track by country.code in my ng-options i get the select list correctly with values set correctly
<option value="?" selected="selected"></option>
<option value="US">United States</option>
<option value="CA">Canada</option>
<option value="MX">Mexico</option>
but i am unable to set a default from my controller
$scope.selectedCountry = "Canada";
or
$scope.selectedCountry = "CA";
Does anyone know how i can fix this issue.
With track by expression, you can omit any other properties and set the default value like this:
$scope.selectedCountry = { code: "CA" };
Hope this helps.
EDIT: If you would like the value of $scope.selectedCountry to be just a string (i.e. 'US', 'CA, or 'MX'), there is no need to use track by, you could use an ng-options like this:
<select ng-model="selectedCountry" name="selectedCountry" id="selectedCountry" ng-options="country.code as country.country for country in countries" ng-change="onCountryChange()" required></select>
Example Plunker: http://plnkr.co/edit/QBRoV09sAlufSffpPPpJ?p=preview

Categories