I am trying to populate a select element from JSON, but the JSON is formatted in such a way that the keys hold valuable information. I do not have control over the data format.
I am trying to iterate over the JSON and and grab the key names for the top-level objects in the array. The problem is that because it is an object, I can't seem to grab just its name -- Object.keys() does not work within ng-options due to scoping.
I've tried many variations on the following, with no luck.
<select ng-model="$ctrl.vals"
ng-options="val as key for (key, val) in $ctrl.data"
ng-change="$ctrl.onChange()" name="{{$ctrl.name}}"
size="{{$ctrl.data.length}}" multiple>
</select>
The above returns "0", because it's formatted as 0: [object object]. The closest I have been able to get is [Object Object] returned, but I want the key of that object, and am not sure how to get it.
I have data formatted like this (sample data, not real):
{
"Games": [{
"Name": "Warhammer 40k 8th Edition",
"Factions": [{
"Space Marines": {
"Units": [{
"Name": "Primaris Space Marine Captain",
"Number": 1,
"Cost": -1,
"Ability": "When captain enters play you win",
"AddOns": [{
"Name": "My AddOn",
"Cost": 0,
"Text": "Add an extra Captain",
"IsSelected": false
}],
"Gear": [{
"Name": "Frag Grenade",
"Cost": 0
}]
}]
}
}]
}]
}
In the context of the JSON above, I want to pass in Factions and see the text "Space Marines" as an option. What am I missing?
If $ctrl.data
in your snippets refers to the "Factions"
property value as you've written, then the ng-options
expression you've used isn't compatible (ie the ... for (key, value) in ...
form would require $ctrl.data
to be an object, which it isn't).
Subsequently, you should use the array expression form for ng-options
, and then you can supply additional functions to rip out the label and model that will be bound when a user selects a particular option.
Here's how you might go about it:
angular .module('app', []) .controller('ctrl', function () { const $ctrl = this; $ctrl.modelFor = function (obj) { const [key] = Object.keys(obj); return key ? obj[key] : null; }; $ctrl.labelFor = function (obj) { const [key] = Object.keys(obj); return key; }; $ctrl.data = [{ "Space Marines": { "Units": [{ "Name": "Primaris Space Marine Captain", "Number": 1, "Cost": -1, "Ability": "When captain enters play you win", "AddOns": [{ "Name": "My AddOn", "Cost": 0, "Text": "Add an extra Captain", "IsSelected": false }], "Gear": [{ "Name": "Frag Grenade", "Cost": 0 }] }] } }]; });
<div ng-app="app" ng-controller="ctrl as $ctrl"> <select ng-model="$ctrl.vals" ng-options="$ctrl.modelFor(obj) as $ctrl.labelFor(obj) for obj in $ctrl.data"></select> <pre>{{ $ctrl.vals }}</pre> </div> <script src="https://unpkg.com/angular@1.7.8/angular.min.js"></script>
As an aside, your data looks a bit odd. If each item of $ctrl.data
can have multiple keys, then this approach will arbitrarily select the first one (ie ordering isn't guaranteed when iterating over keys).
Transform the data:
$ctrl.mapped = $ctrl.data.map(_ => {
var entry = Object.entries(_)[0];
return { key: entry[0], value: entry[1] };
});
Then use it in the HTML:
<select ng-model="$ctrl.vals"
ng-options="item.value as item.key for item in $ctrl.mapped"
ng-change="$ctrl.onChange()" name="{{$ctrl.name}}"
size="{{$ctrl.data.length}}" multiple>
</select>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.