icebreaker icebreaker - 4 months ago 11
AngularJS Question

What would be angular ng-option equivalent of this select?

I am struggling to get this into an ng-option. Is it even possible?

<select ng-model="detail_type_id">
<optgroup ng-repeat="type in data.detailTypes" label="{{type.name}}">
<option ng-repeat="t in type.children" value="{{t.id}}">{{t.name}}</option>
</optgroup>
</select>


DetailTypes looks like this:

[
{"id":7,
"parent_id":null,
"name":"Contact",
"children":[
{"id":8,
"parent_id":7,
"name":"Address",
"children":[]
},
{"id":12,
"parent_id":7,
"name":"Something else",
"children":[]
}
]},
{"id":16,
"parent_id":null,
"name":"Other",
"children":[
{"id":10,
"parent_id":16,
"name":"Remarks",
"children":[]}
]
}
]


Child id needs to be selected. Nesting cannot be deeper.

Answer

The ngOptions directive does not work with multidimensional objects. So you need to flatten your array to use it.

I wrote a filter for that:

app.filter('flatten' , function(){
  return function(array){
    return array.reduce(function(flatten, group){
      group.children.forEach(function(child){
        child.groupName = group.name;
        flatten.push(child)
      })
      return flatten;
    },[]);
  }
})

And the HTML part would be like this:

<select ng-model="detail_type_id"
        ng-options="item.id as item.name 
                    group by item.groupName for item 
                    in data.detailTypes | flatten track by item.id">
</select>

Plunker (version #1 with filter): https://plnkr.co/edit/dxi7j8oxInv2VRJ1aL7F

I also modified your object to be like this:

[{
  "id": 7,
  "parent_id": null,
  "name": "Contact",
  "children": [{
    "id": 8,
    "parent_id": 7,
    "name": "Address",
    "children": []
  }, {
    "id": 12,
    "parent_id": 7,
    "name": "Something else",
    "children": []
  }]
}, {
  "id": 16,
  "parent_id": null,
  "name": "Other",
  "children": [{
    "id": 10,
    "parent_id": 16,
    "name": "Remarks",
    "children": []
  }]
}]

EDIT:

After suggestion I wrote another version without the filter, but flattening the array inside the controller.

Additional Controller JS:

$scope.flattenDetailTypes = flattenDetailTypes($scope.data.detailTypes);

  function flattenDetailTypes(array){
    return array.reduce(function(flatten, group){
      group.children.forEach(function(child){
        child.groupName = group.name;
        flatten.push(child)
      })
      return flatten;
    },[]);
  }

Markup:

<select ng-model="detail_type_id"
        ng-options="item.id as item.name group by item.groupName for item in flattenDetailTypes track by item.id"></select>

Plunker (version #2 without filter): https://plnkr.co/edit/D4APZ6

Comments